ヘッドレス RaspberryPi ZeroW のブートディスク作成（Wi-Fi 設定済み SSH 有効済み）と設定

<h1><sub><sup>「テレビもねえ、マウスもねぇ、USB キーボードは何者だ？」な環境で、RaspberryPi Zero のセットアップが必要な時のサバイバル術</sup></sub></h1>

> ノートパソコンを持って参上したら、新しいラズパイ ZeroW と電源だけ渡され「よろしく」と言われました。
>
> しかしながら、HDMI to HDMI mini ケーブルどころか、モニタなし、マウスなし、キーボードなしの環境で、**ラズパイ Zero W の起動ディスク（SDカード）を自前のパソコン上でセットアップしたい**のです。
>
> どうしよう。

あるのは「ヘッドレスのラズパイ」「Wi-Fi 環境」「ノートパソコン」と「microSD カードライター」だけ。

有線 LAN なんて、もちろんないよ。

- RPi 3B 以降でも同じ手順でできます。[こちら](https://qiita.com/KEINOS/items/afce3b718627267e143f)にラズパイ 3 の古いサバイバル記事があります。
  - https://qiita.com/KEINOS/items/afce3b718627267e143f @ Qiita

:::note info
2022/04/21 追記: 最新の RaspberryPi OS（v11, Bullseye）では、**デフォルトユーザーの `pi` がなくなりました**。GUI 版であれば、初回起動時にアカウントの作成を聞いてくるのですが、ヘッドレス（CUI 版、RaspberryPi OS Lite）の場合は、Raspberry Pi Imager の `settings` からデフォルトのアカウントをあらかじめ指定しておく必要があります。

- [An update to Raspberry Pi OS Bullseye](https://www.raspberrypi.com/news/raspberry-pi-bullseye-update-april-2022/) | News @ raspberrypi.com

:::

## TL; DR <sub><sup><sub><sup>（今北産業）</sup></sub></sup></sub>

1. 「初回起動<font color=darkorange>**前**</font>」に SD カードの **`boot` パーティションに以下の2つのファイルを置きます**。
    - 空の `ssh` ファイル（`/boot/ssh`）
    - Wi-Fi のログイン設定ファイル（`/boot/wpa_supplicant.conf`）
2. え？ラズパイの IP アドレス？ まずは `ping raspberrypi.local` で確認してみましょう。
3. え？設定面倒そう？ [Raspberry Pi Imager](https://www.raspberrypi.com/software/) v1.6 から、アカウント・SSH・ WiFi・キーボード・etc. などの設定が[行えるようになりました](https://www.raspberrypi.com/news/raspberry-pi-imager-update-to-v1-6/)。 <font color=red><sub><sup><sup>オススメ!</sup></sup></sub></font>
    - Raspberry Pi Imager を開いたら `settings` ボタンから Advanced Options が開き以下の項目が事前に設定できるようになりました<br>![RaspberryPiImager_SSH.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78776/aebe4c42-6a55-9d94-4906-50c78c4677e9.png)
    - `Keyboard layout:` は日本語 104 キーボードの場合は `jp`


> <sup>🐒 &nbsp; さらにもっと**細かい設定を事前に自動化したい**場合は `PiBakery` というアプリもあります。<br>`PiBakery` は GUI で `boot` イメージをカスタムできるアプリです。SD カードの初回起動時に任意のスクリプトを実行させたり、設定を行えるようにできます。ただし、流れや仕組みを把握していないと安定した実行は難しく、正直「素人にはオススメできない」アプリです。まずは本記事のような手作業に慣れてきてからの利用をオススメします。ススメておいて何ですが、私にはレベルが高く使っていません。</sup>
>
> - [PiBakery](https://www.pibakery.org)
>   - 参考文献: [Having Raspbian run startup scripts from the /boot partition](https://lb.raspberrypi.org/forums/viewtopic.php?t=131443#p1415626) | フォーラム @ ラズパイ公式

[^ssh]: **SSH 接続とは**、`ssh` コマンドを使った別マシンへの接続を言います。<br><br>FTP ソフトで別マシンに接続するときは `FTP` プロトコル[^protocol]。Web ブラウザなどの HTTP/HTTPS ソフトで別マシンに接続するときは `http`/`https` プロトコルのように、`ssh` プロトコルで別マシンに接続するためには `ssh` ソフトが必要です。`ssh` ソフトは一般的にコマンド・ツールとして提供されており、コマンド・ライン／ターミナルなどから実行し、接続します。一度接続すると、その接続先のローカルでコマンド操作しているのと同じ状態になります。<br><br>**SSH 接続の仕方**は `$ ssh 192.168.1.10` といった書式で行います。`192.168.1.10` は接続先のマシンのアドレスです。ホスト名が使える場合は `$ ssh keinos-no-macbookpro.local` や `$ ssh keinos-machine1` といった「ネットワーク一覧」で表示されるコンピューター名でアクセスできます。インターネットなど、DNS でホスト名（ドメイン名）を管理している場合は、そのホスト名でアクセスできます。例えば GitHub のサーバーの場合は `ssh github.com` になります。<br><br>この時、接続先のサーバーは [SSH サーバー](https://ja.wikipedia.org/wiki/Secure_Shell)が使えるようにします。つまり、OpenSSH などのサーバーをインストールし、SSH 接続用のポート[^port]をファイアーウォールから解放後、SSH サーバーをサービス（SSH デーモン）を起動しておく必要があります。ラズパイの場合は、OpenSSH がインストール済みなので、SSH を有効にするだけで使えます。<br><br>また、SSH 接続する場合は、接続先の登録済みユーザーとしてアクセスします。基本的に、接続時にどのユーザーで接続するか聞かれますが、ユーザーを指定しながら接続も可能です。その場合は `$ ssh keinos@192.168.1.10` （ユーザー=`keinos`）といった具合です。<br><br>[ベーシック認証](https://ja.wikipedia.org/wiki/Basic%E8%AA%8D%E8%A8%BC)同様に、パスワードも添えて接続することも可能です。その場合は `ssh keinos:myPassword@192.168.1.10` といったコマンドを打ちます。しかし、パスワードが見えてしまっているので「ターミナルのログなどからわかってしまう」ということでもあります。それを回避する１つとして公開鍵・秘密鍵認証（下記参照）があります。

[^protocol]: **プロトコルとは**、共通ルールのことで、そのルールに従わないと参加・利用できないもの全般を言います。<br>・ [プロトコルとは（Protocol の本来の意味から技術英語へ）](https://qiita.com/KEINOS/items/cb7f629268b90ef6493d) @ Qiita

[^port]: **ポートとは**、パソコンやサーバーが外部と通信する時のチャンネル番号のようなものです。１台のテレビで複数チャンネルが見れるように、１つのサーバーに複数のプロトコルで接続できるように、各々にポートと番号が割り当てられています。<br><br>どのポートに、どのサービス（プロトコル）を割り当てるかは基本的にサーバー側の自由です。しかし、テレビ同様、NHK は１チャンネル、フジテレビは８チャンネルと、ポートにも一般的に割り当てられる番号があり[ウェルノウンポート番号（よく知られたポート番号）](https://ja.wikipedia.org/wiki/TCP%E3%82%84UDP%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E3%83%9D%E3%83%BC%E3%83%88%E7%95%AA%E5%8F%B7%E3%81%AE%E4%B8%80%E8%A6%A7#%E3%82%A6%E3%82%A7%E3%83%AB%E3%83%8E%E3%82%A6%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%88%E7%95%AA%E5%8F%B7_(0%E2%80%931023))と呼ばれます。例えば、`http` は 80 番、`ssh` は 22 番といった番号が使われます。地方だとテレビのチャンネル番号が変わるように、必ずしも `ssh` のポートが 22 と、同じわけではないので注意します。

## TS; DR <sub><sup><sub><sup>（ヘッドレス・ラズパイとラズパイ OS Lite で遊ぶコマケーこと）</sup></sub></sup></sub>

- おおまかな流れ
    1. microSD カードに OS イメージを焼く
    2. <font color=darkorange>SSH 接続許可と Wi-Fi 接続情報を microSD カードに書き込む **←ここがポイント**</font>
    3. microSD カードをラズパイに指す
    4. ラズパイに [SSH で接続する](#%E3%83%A9%E3%82%BA%E3%83%91%E3%82%A4%E3%81%B8-ssh-%E6%8E%A5%E7%B6%9A%E3%82%92%E3%81%99%E3%82%8B)（ユーザ: `pi`、パスワード: `raspberry`）
    5. 各種設定する
    6. 困った時には「[その他の情報／切り分け用メモ](#%E7%9F%A5%E3%81%A3%E3%81%A6%E3%81%8A%E3%81%8F%E3%81%A8%E4%BE%BF%E5%88%A9%E3%81%AA%E3%82%B5%E3%83%90%E3%82%A4%E3%83%90%E3%83%AB%E8%A1%93)」

### 基本情報をひかえておく

設定及び設置したい環境の、以下の Wi-Fi 情報をあらかじめ調べておきます。

- `SSID`（アクセスポイント名）
- アクセス・キー（WiFi 接続のパスワード）
- **注意／備考**:
  - **ラズパイ Zero の WiFi は 2.4GHz** の `IEEE 802.11 b/g/n` のみ利用可能です。
  - WiFi のセキュリティ（認証と暗号化）は `WPA2/PSK, AES` を想定しています。**`WEP` は使えません**。
  - ネットワーク上に他にも動いているラズパイがある場合は、そのラズパイの設定ファイルを流用可能です。（`/etc/wpa_supplicant/wpa_supplicant.conf`）

### Raspberry Pi Imager/balenaEtcher のインストール

SD カードに OS イメージを書き込むツールには２つの方法が推奨されています。公式アプリを使うか、公認アプリを使うかです。

- ラズパイ公式アプリ [Raspberry Pi Imager](https://www.raspberrypi.org/downloads/) @ RaspberryPi.org
- ラズパイ公認アプリ [balenaEtcher](https://www.balena.io/etcher/) @ balena[^etcher]

OS ダウンローダー、フォーマッター、ライターの全部盛りである公式アプリの `Raspberry Pi Imager` をおすすめします。特に v1.6 以降からは `.ssh` や WiFi 設定なども隠しモード（`shift`+`ctl`+`x`）から行えるようになったからです。（ただ従来の方法もサバイバル知識として知っておいた方が潰しが効きます）

[^etcher]: **「`balenaEtcher`」（旧 `Etcher`）とは** [Balena.io](https://www.balena.io/)（旧 Resin.io）によってメンテナンスされている [Electron](https://ja.wikipedia.org/wiki/Electron_(%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2)) で開発された**オープンソースのイメージ書き込みアプリ**です。ISO, IMG や ZIP などのアーカイブされたイメージを SD カード、USB メモリなどに書き込め、[ラズパイ公式も推奨](https://www.raspberrypi.org/documentation/installation/installing-images/README.md)しています。

いずれのアプリも、Windows／Mac／Linux で使えます。balenaEtcher をインストールしたい場合、macOS 環境で [Homebrew](https://brew.sh/index_ja) が入っている場合は `brew` コマンドでインストール可能です。

```shell-session:balenaEtcher
$ brew cask install balenaetcher
```

:::note info 
<sub><sup>🐒 &nbsp; 以前までは OS のインストールには <a href="https://www.raspberrypi.org/downloads/noobs/" target="_blank">NOOBS</a> が推奨されていました。現在でも利用可能で、どれを使うかは一長一短があります。
NOOBS は、強いて言えば <code>/boot</code> パーティションに OS インストーラーが入っているようなもので、OS ではありません。NOOBS を SD カードにインストールして起動すると、NOOBS が立ち上がり WiFi などのネットワークの設定が行え、オンラインで任意の OS のダウンロードやインストールが行えます。選択の自由度が高い代わりに、それらの操作はモニタ上（GUI 上）で行うため、今回のようなモニタがない場合には適しません。
ダウンロードした <strong>OS のイメージを焼き付けるだけであれば balenaEtcher がシンプル</strong>です。逆に言うと、それ以上は出来ないので OS イメージのダウンロードは各自で行う必要があり、SD カードをフォーマットする場合も、<a href="https://www.sdcard.org/jp/downloads/formatter/index.html" target="_blank">SD カードの公式フォーマット・アプリ</a>が必要になります。
NOOBS のような OS 選択とダウンロード、balenaEtcher のようなイメージの焼き付け、そして SD カードのフォーマッターを１つにしたものが Raspberry Pi Imager です。いずれのアプリもインストールしていない場合は、<strong>Raspberry Pi Imager をおすすめします</strong>。
</sup></sub>
:::

### OS イメージのダウンロード

Raspberry Pi Imager を使う場合はアプリから OS イメージを選択・ダウンロードできるので次に進みます。

<details><summary>balenaEtcher を使いたい場合</summary><div>

balenaEtcher を使う場合は、焼き付ける OS イメージをダウンロードしておかないと行けません。

以下のいずれかよりイメージの ZIP のダウンロードを行います。ちなみにダウンロードした **ZIP は解凍せず、そのままで大丈夫**です。

- [最新 Raspberry Pi OS（旧 Raspbian）](https://www.raspberrypi.org/software/operating-systems/) @ RaspberryPi 公式
- [Buster Lite 2020-02-13 (Raspbian 10)](https://downloads.raspberrypi.org/raspbian_lite/images/raspbian_lite-2020-02-14/) @ RaspberryPi 公式
- [Stretch Lite 2019-04-09 (Raspbian 9)](https://downloads.raspberrypi.org/raspbian_lite/images/raspbian_lite-2019-04-09/) @ RaspberryPi 公式
- 旧バージョンの Raspbian @ RaspberryPi 公式：
  - [Raspbian Lite ダウンロード一覧](https://downloads.raspberrypi.org/raspbian_lite/images/) 
  - [Raspbian Full（デスクトップ版）ダウンロード一覧](https://downloads.raspberrypi.org/raspbian_full/images/)

ダウンロードした ZIP が壊れていたり改ざんされていると元も子もないので、ファイルのチェックサムを確認します。（詳しくは下部「その他情報」参照）

```shell-session:ダウンロードとチェックサムの検証
$ # 本体 ZIP とチェックサムのダウンロード （2019-09-26-raspbian-buster-lite）
$ curl https://downloads.raspberrypi.org/raspbian_lite/images/raspbian_lite-2019-09-30/2019-09-26-raspbian-buster-lite.zip
$ curl https://downloads.raspberrypi.org/raspbian_lite/images/raspbian_lite-2019-09-30/2019-09-26-raspbian-buster-lite.zip.sha256
$ # チェックサムの検証
$ shasum -c ./2019-09-26-raspbian-buster-lite.zip.sha256
2019-09-26-raspbian-buster-lite.zip: OK
```

> <sup>🐒 &nbsp; `Buster Lite` `Stretch Lite` `Raspberry Pi OS Lite` の、なんとか `Lite` は GUI 関連のファイルの入っていない **CUI 専用の軽量版 OS** です。OS インストール後もヘッドレスで利用する場合（モニタなどを接続しないで主に SSH 接続で作業する場合）に便利です。<br>逆に後日モニタも繋げてデスクトップ（GUI）も使いたい場合は、`with desktop` のフルバージョン版をダウンロードしてください。ただし SSH で `raspi-config` をあらかじめ実行していても初回起動時にデスクトップに表示されるウィザードは一度一通り実行しておかないといけないことに注意です。</sup>

</div></details>

### OS のインストール（イメージの書き込み）

<div><img width="49%" alt="Raspberry Pi Imagerの起動画面" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78776/e7d6e2d7-7e86-8a01-4d54-647e2ed6a341.png"><img width="49%" alt="balenaEtcherの起動画面" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78776/931ffb31-2f92-c319-a462-5f8d7e6e1dab.png"></div>

上記、Raspberry Pi Imager と balenaEtcher どちらも左から順番に設定していくだけで、SD カードに `boot` という名前で初期化され OS がインストールされます。

- Raspberry Pi Imager v1.6 以降では、次項の SSH や WiFi の設定などもこの画面で行えるようになりました。（次項参照）

<details><summary>balenaEtcher を使う場合</summary>
<div>
フォーマットが必要な場合は[公式アプリ](https://www.sdcard.org/jp/downloads/formatter/index.html)などで事前に [SD カードを FAT32 フォーマット](https://qiita.com/KEINOS/items/43394e4bd3c8fcfb5ee8#sd-%E3%82%AB%E3%83%BC%E3%83%89%E3%81%AE%E5%88%9D%E6%9C%9F%E5%8C%96)してください。Raspberry Pi Imager の場合はアプリ内からフォーマット可能です。

1. SD カードリーダーに microSD カードを入れマシンに繋げる。
2. balenaEtcher を起動し、"`Select Image`" でダウンロードした `zip` ファイルを選択して開く。<br>（バックアップ/リカバリーの場合は ISO ファイルを選ぶ）
3. "`Select Target`" で書き込み先に SD カードを選ぶ。
4. 設定を確認し「`Flash!`」ボタンを押して書き込む。（管理者パスワードを聞かれます）
5. `boot` の確認。<br>`Finder`/`Explorer`/`Volumes` などを見て、`boot` のディスクがマウントされていない場合は、SD カードリーダーを抜き差しして再認識させます。

- **注意**: お約束ですが SD カードは完全に初期化されるので、ドライブを間違えると消えちゃいます。`$ diskutil` などでドライブ名を丹念に確認しておきましょう。また、成功（`SUCCESS!`）と出ていても、よく見るとビックリマークが出ていてチェックサムでエラーが発生した<ruby>云々<rt>うんぬん</rt></ruby>のメッセージが出ることがあります。その場合は、SD カードが不良品である可能性もあります。その可能性がある場合は、下部にある「SD カードの不具合確認」を参照ください。

> <sup>🐒 &nbsp; Mac や Windows からは `boot` パーティションしか見えませんが、実際には 2 つのパーティションに分かれています。[FAT32 形式](https://ja.wikipedia.org/wiki/File_Allocation_Table#FAT32) でフォーマットされた `boot` パーティションと、[EXT4 形式](https://ja.wikipedia.org/wiki/Ext4)でフォーマットされた `root`（`rootfs`）パーティションです。ラズパイのブートローダーは GPU に焼き付けられており、FAT フォーマットからしか起動できない[仕様](https://www.raspberrypi.org/documentation/installation/sdxc_formatting.md)です。初回起動時に EXT4 パーティションを限界まで拡張し、OS イメージをマウントして展開します。</sup>
>
> - <sup>オススメの記事：[Raspberry Piで最小サイズのバックアップを作成する](https://dev.classmethod.jp/hardware/raspberrypi-backup-restore/) @ Developers.IO</sup>

</div></details>

### Wi-Fi 設定ファイルと SSH 接続許可ファイルの設置

:::note info
Raspberry Pi Imager v1.6 では <code>shift</code>+<code>ctl</code>+<code>x</code> で以下と同じ操作を GUI 上でできるようになりました。以下は balenaEtcher などの他のイメージ・ライターで書き込む場合のサバイバル知識です。GUI が裏で何をしているのか参考にしてください。
:::

以下の２つのファイルを SD カード（マウントされたディスク `boot`）内に作成します。

- `ssh` （`touch` コマンドで空のファイルを作成します。`$ touch ssh`）
- `wpa_supplicant.conf`

    ```conf:/Volumes/boot/wpa_supplicant.conf
    country=JP
    ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
    update_config=1
    network={
        ssid="<ここにSSID名>"
        psk="<ここにWiFiの接続パスワード>"
    }
    ```

    - パスワードは暗号化もできますが**`psk` のパスワードは平文で構いません**。理由は以下を参照。
        - 「[wpa_supplicant.conf に書く PSK を wpa_passphrase コマンドで暗号化する意味はあんまし無い](https://qiita.com/rukihena/items/7c0087b56ccfbc05c793)」 @ Qiita
    - **`country=JP` を忘れると<font color=red>日本国内ではつながらない</font>**ので注意。

この時、SSH 接続用の公開・秘密鍵が作成済みの場合は、公開鍵もコピーしておくと後が楽です。（`~/.ssh/id_rsa.pub` など）

```bash:id_rsa.pubのコピー例
cp ~/.ssh/id_rsa.pub /Volumes/boot/id_rsa.pub
```

#### 複数アクセスポイントを事前に登録しておく

自宅と現場など、準備している環境と設置先で Wi-Fi が異なる場合は `network` を追加します。ここでも `country=JP` を入れておくのがポイント。

```conf:/Volumes/boot/wpa_supplicant.conf
country=JP
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
    ssid="<ここにWiFi①のSSID名>"
    psk="<ここにWiFi①の接続パスワード>"
}
network={
    ssid="<ここにWiFi②のSSID名>"
    psk="<ここにWiFi②の接続パスワード>"
}
```

<details><summary>`/Volumes/boot` ディレクトリ内のファイル一覧</summary>
<div>

```shell-session
$ ls -la boot
total 43252
drwxrwxrwx@ 1 admin  staff     2560  9 23 10:21 .
drwxr-xr-x+ 8 root   wheel      256  9 23 10:19 ..
drwxrwxrwx  1 admin  staff      512  9 23 10:19 .fseventsd
-rwxrwxrwx  1 admin  staff    18693  3  9  2018 COPYING.linux
-rwxrwxrwx  1 admin  staff     1494  3  9  2018 LICENCE.broadcom
-rwxrwxrwx  1 admin  staff    18974  4  8 10:25 LICENSE.oracle
-rwxrwxrwx  1 admin  staff    23315  9 19  2018 bcm2708-rpi-0-w.dtb
-rwxrwxrwx  1 admin  staff    23071  9 19  2018 bcm2708-rpi-b-plus.dtb
-rwxrwxrwx  1 admin  staff    22812  9 19  2018 bcm2708-rpi-b.dtb
-rwxrwxrwx  1 admin  staff    22589  9 19  2018 bcm2708-rpi-cm.dtb
-rwxrwxrwx  1 admin  staff    24115  9 19  2018 bcm2709-rpi-2-b.dtb
-rwxrwxrwx  1 admin  staff    25914  2 18  2019 bcm2710-rpi-3-b-plus.dtb
-rwxrwxrwx  1 admin  staff    25311  9 19  2018 bcm2710-rpi-3-b.dtb
-rwxrwxrwx  1 admin  staff    24087  9 19  2018 bcm2710-rpi-cm3.dtb
-rwxrwxrwx  1 admin  staff    52296  2 18  2019 bootcode.bin
-rwxrwxrwx  1 admin  staff      190  4  8 10:25 cmdline.txt
-rwxrwxrwx  1 admin  staff     1590  4  8 09:56 config.txt
-rwxrwxrwx  1 admin  staff     6701  4  1 14:03 fixup.dat
-rwxrwxrwx  1 admin  staff     2622  4  1 14:03 fixup_cd.dat
-rwxrwxrwx  1 admin  staff     9750  4  1 14:03 fixup_db.dat
-rwxrwxrwx  1 admin  staff     9752  4  1 14:03 fixup_x.dat
-rwxrwxrwx  1 admin  staff      145  4  8 10:25 issue.txt
-rwxrwxrwx  1 admin  staff  4698056  2 18  2019 kernel.img
-rwxrwxrwx  1 admin  staff  4944992  2 18  2019 kernel7.img
drwxrwxrwx  1 admin  staff    13312  4  8 10:25 overlays
-rwxrwxrwx  1 admin  staff        0  9 23 10:20 ssh <------------------ 作成
-rwxrwxrwx  1 admin  staff  2873444  4  1 14:03 start.elf
-rwxrwxrwx  1 admin  staff   683460  4  1 14:03 start_cd.elf
-rwxrwxrwx  1 admin  staff  4830756  4  1 14:03 start_db.elf
-rwxrwxrwx  1 admin  staff  3774980  4  1 14:03 start_x.elf
-rwxrwxrwx  1 admin  staff      145  9 23 10:21 wpa_supplicant.conf <-- 作成
```

</div></details>

### ラズパイへ microSD を挿す

ローカルの micorSD を取り出し（`boot` をアンマウントし）、ラズパイに挿す。

LED が激しい点滅を始めれば次へ。定期的な点滅の場合は SD カードが壊れている可能性があります。（下記切り分けメモ参照）

### ラズパイへ SSH 接続をする

LED が「点灯」した（激しい点滅が落ち着いた）ら、ロカールからリモートへ SSH 接続してみます。

```bash:piユーザでSSH接続
ssh pi@raspberrypi.local
```

この時点ではパスワードを聞かれます。**デフォルトのユーザは `pi` で、初期パスワードは `raspberry`** です。

接続先ですが、Raspbian OS は [Bonjour](https://ja.wikipedia.org/wiki/Bonjour) 互換の [Avahi-daemon](https://ja.wikipedia.org/wiki/Avahi) も動いているので、ホスト名に `raspberrypi.local` と [mDNS](https://en.wikipedia.org/wiki/Multicast_DNS) でアクセスできます。

:::note info
<sub><sup>🐒 &nbsp; Windows 10 の場合はデフォルトで Bonjour 互換ではなくなりました。
以前までは<a href="https://opensource.apple.com/tarballs/mDNSResponder/" target="_blank">アップル社のオープンソースの mDNS</a> が入っていたのですが、2017 年の Fall Creator Update 以降でサポートしなくなりました。しかし、iTunes や Adobe 製品などをインストールすると入っていたりするので、まずは <code>raspberrypi.local</code> で接続を試してみてください。NG だった場合、後述する Bonjour をインストールするか、ラズパイの IP アドレス直打ちに変えてください。<a href="#%E3%81%A7%E3%81%AF%E6%AD%A3%E5%B8%B8%E3%81%AAsd-card%E3%82%92%E7%94%A8%E6%84%8F%E3%81%A7%E3%81%8D%E3%81%9F%E3%81%A8%E3%81%97%E3%81%A6%E3%81%A9%E3%81%86%E3%82%84%E3%81%A3%E3%81%A6%E8%B5%B7%E5%8B%95%E3%81%97%E3%81%9F%E3%81%AE%E3%81%8B%E7%A2%BA%E8%AA%8D%E3%81%99%E3%82%8C%E3%81%B0%E8%89%AF%E3%81%84%E3%81%AE%E3%81%8B">コメント欄</a>もご覧になると、ためになります。</sup></sub>
:::

#### Windows10 に Bonjour を入れる

[iTunes のインストーラーをダウンロード](https://www.apple.com/jp/itunes/)して 7-zip で解凍すると、「`Bonjour64.msi`」が入っているので実行してインストールします。

- ラズパイの IP アドレスを確認する[^checkip]

[^checkip]: **ラズパイの IP アドレスを確認する：** [コメント欄を参照](#comment-0fd421fbd85c7a598dc6)してください。基本的に、ルーターの管理画面で DHCP の割り当て済み一覧で、ラズパイ起動前と起動後で確認します。この時、ルーターの DHCP が割り当てを変えないように、固定（ルーターの DHCP 設定でラズパイの MAC アドレスと IP アドレスの割り当て）設定をおすすめします。

#### SSH 公開鍵を転送する

:::note info
RaspberryPi Imager を使っている場合、SSH 接続用の公開鍵は隠しモードの <code>Enable SSH</code> の項目にある "<code>Allow putlic-key〜</code>" フィールドに予めセットできます。<sub><sup><font color=red>オススメ</font></sup></sub>
:::

パスワードでなく SSH 公開鍵認証によるログインをしたい場合は、先に RSA 公開鍵を転送しておくと後が楽です。もしくは SD カードに `ssh` と `wpa_supplicant.conf` ファイルを作成した際に、一緒に置いておいおくのが楽でしょう。

```bash:piユーザーのアカウントに自分の公開鍵を登録する
ssh-copy-id -i ~/.ssh/id_rsa.pub pi@raspberrypi.local
```

また、`ssh` の認証は「公開鍵認証 ONLY」の設定にしておき、パスワード認証のログインおよび `root` ユーザのログインを無効にすることをオススメします。それだけでセキュリティが段違いに強くなります。

- <sup>詳しくは、記事下部「[その他情報](#ssh-%E6%8E%A5%E7%B6%9A%E3%81%A7%E5%85%AC%E9%96%8B%E9%8D%B5%E3%82%92%E4%BD%BF%E3%81%86)」参照</sup>

```shell-session:ログイン例
$ ssh pi@raspberrypi.local
The authenticity of host 'raspberrypi.local (fe80::3d17:29aa:77ba:c7ef%en0)' can't be established.
ECDSA key fingerprint is SHA256:czhT7ZhNO/cRKz5sTOFlltg8BUXmCHwiNLjtfgIzkmU.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'raspberrypi.local,fe80::3d17:29aa:77ba:c7ef%en0' (ECDSA) to the list of known hosts.
pi@raspberrypi.local's password:         ← ここでパスワードを入力
Linux raspberrypi 4.14.98+ #1200 Tue Feb 12 20:11:02 GMT 2019 armv6l

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
-bash: warning: setlocale: LC_ALL: cannot change locale (ja_JP.UTF-8)
-bash: warning: setlocale: LC_ALL: cannot change locale (ja_JP.UTF-8)

SSH is enabled and the default password for the 'pi' user has not been changed.
This is a security risk - please login as the 'pi' user and type 'passwd' to set a new password.

-bash: warning: setlocale: LC_ALL: cannot change locale (ja_JP.UTF-8)
pi@raspberrypi:~ $ 
```

- [SSH 接続時「WARNING: POSSIBLE DNS SPOOFING DETECTED」と表示される場合](#ssh-%E6%8E%A5%E7%B6%9A%E6%99%82warning-possible-dns-spoofing-detected%E3%81%A8%E8%A1%A8%E7%A4%BA%E3%81%95%E3%82%8C%E3%82%8B%E5%A0%B4%E5%90%88)は、[その他の情報／切り分け用メモ](#%E3%81%9D%E3%81%AE%E4%BB%96%E3%81%AE%E6%83%85%E5%A0%B1%E5%88%87%E3%82%8A%E5%88%86%E3%81%91%E7%94%A8%E3%83%A1%E3%83%A2)をご覧ください。

### ラズパイ本体の設定を行う

以下からは、SSH 経由によるラズパイ内での操作です。

#### `raspi-config` の設定

無事 SSH ログインできたらアップデート前に `$ sudo raspi-config` コマンドで、ホスト名（コンピューター名）と日本語の設定などを行います。

特に Locale を設定しないと、のちに `Can't set locale` や `cannot change locale (ja_JP.UTF-8)` のワーニングの嵐が連発します。

- `System Options`
    - `Password:Change password for the 'pi' user` -> `pi` ユーザーのパスワードを変更しておく
- `Localisation Options`
    - `Locale` -> `ja_JP.UTF-8` にチェックを入れ `Default locale` に設定する
    - `Timezone` -> アジア, 東京
    - `Keyboard` -> 無視（キーボードないので設定しなくてもおk）
    - `WLAN Country` -> JP（おそらく設定済みだが念のため）
- `Update` でツールをアップデートしておく
- `System Options`
    - `Hostname` -> `raspberrypi` から任意のホスト名に変更する。（後でローカルの `~/.ssh/known_hosts` から古い `raspberrypi.local` の接続を削除します）

#### 完全ヘッドレス向けの `raspi-config` 追加設定

- `Display Options`
    - `Resolution` で 画面解像度を `640 x 480` or `800 x 600` など低めにする
- `Performance Options`
    - `GPU Memory` を 64 -> 16 に変更する

通常モニタを HDMI 接続する予定がない場合は、**画面解像度と GPU メモリ使用量を落とすことで安定性を増すことができる**のでオススメです。

というのも、GUI なしの Raspbian Lite/RaspberryPi OS Lite とは言え CUI なのでモニタを接続するとターミナルが描画されています。解像度を落とし、GPU メモリ使用量を落とすことでグラフィック関連のリソースを他に回せるぶん、安定します。微々たるものかもしれませんが、低電力で動くラズパイ・ゼロなので意外に効果的です。

なお、GPU をグラフィックス以外でも演算処理用に使う類いのアプリやライブラリを使う場合は、GPU メモリは大きくしておく必要があります。

### NTP の設定を確認する

忘れがちなのが NTP の設定です。

`raspi-config` でタイムゾーンが設定されていれば時刻も同期してくれるのですが、デフォルトで NTP が海外の Debian の NTP サーバーです。そのため、時刻が合うまでの調整パケットの送受信がいささか多めに発生します。

**この記事は、ラズパイ Zero を前提としているので、起動時の負荷は下げたい**ところです。

- [NTP の設定を国内の NICT などに設定する](#ntp%E6%99%82%E5%88%BB%E3%81%AE%E5%90%8C%E6%9C%9F%E3%82%92-nict-%E3%81%AB%E3%81%82%E3%82%8F%E3%81%9B%E3%82%8B)

### アップデートを行う

以下でパッケージ情報のアップデートと、既存（インストール済み）パッケージのアップグレードをして更新します。

```bash:個別アップデート
sudo apt-get update --yes       // 最新のパッケージ情報や更新情報を取得
sudo apt-get full-upgrade --yes // 既存のパッケージをすべて更新
```
```bash:上記のワンライナー
sudo apt-get update --yes && sudo apt-get full-upgrade --yes && sudo reboot
```

- アップデートが遅いと感じる場合は[日本国内のミラーサーバーに変更](#apt-%E3%81%8C%E9%81%85%E3%81%84)してみてください。
- セキュリティやパッケージのアップデートを定期実行させたい場合は [apt の自動更新](#apt-%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E3%81%AE%E8%87%AA%E5%8B%95%E6%9B%B4%E6%96%B0)を有効にしてください。

<details><summary>rpi-update について</summary><div>

#### rpi-update について

`apt` などのパッケージ以外に、Linux カーネルをアップグレードする `rpi-update` コマンドがあります。

基本的に `rpi-update` コマンドによるファームウェア（カーネル）のアップグレードは[推奨されていません](https://www.raspberrypi.org/documentation/raspbian/applications/rpi-update.md)。**パッケージやアプリなどで指示がある場合のみ**行います。

しかし USB ハードウェアや [MIDI](https://ja.wikipedia.org/wiki/MIDI) 関連で `libudev-dev` のインストールを求めてくるものや、特に [SDL](https://ja.wikipedia.org/wiki/SDL)（`libsdl`）を扱う可能性がある場合はアップグレードしておいた方が良いことが多くあります。SDL とはマルチメディア関連のライブラリです。

というのも、今回のように X11 関連（デスクトップ系のアプリ）を入れない RaspberryPi OS Lite を使う場合、モニター（のターミナル）にイメージを描画する場合は SDL2 を使って描画することになります。

俺様アプリの開発や、使用するライブラリで SDL2 を使う場合、もしくは GUI 向けにビルドされているアプリを GUI なし設定でソースから再ビルドする必要がある場合は、<ruby>コンパイル<rt>困憊る</rt></ruby>前に備えて、まっさらなうちにアップグレードしておきます。

```shell-session:ファームウェアとカーネルの更新（要再起動）
$ sudo rpi-update && sudo reboot now
```

> <sup>🐒 &nbsp; `rpi-update` は Linux カーネルを最新の状態にします。しかし、RaspberryPi Zero W のアーキテクチャ（CPU）は `ARMv6l` です。つまり、他のラズパイ（`ARMv7l`）と違うためコンパイル済みのパッケージ提供が間に合わないことが多くあります。そのため盲目的に（ラズパイ ZERO の場合は特に） `rpi-update` はせず、まずはデフォルトのファームウェアで動作確認し、動かず、ファームウェアのアップデートで解決したと情報がある場合のみファームウェアをアップデートします。</sup>

</div></details>

### 最低限必要なパッケージ（アプリ）をインストールする

`vi` が使いづらい場合に `vim` など、設定作業に必要な最低限のものをインストールしておきます。

> <sup>🐒 &nbsp; 後述する[リカバリー・ディスク作成](#sd-%E3%82%AB%E3%83%BC%E3%83%89%E3%81%AE%E3%83%90%E3%83%83%E3%82%AF%E3%82%A2%E3%83%83%E3%83%97%E3%83%AA%E3%82%AB%E3%83%90%E3%83%AA%E3%83%BC%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8%E3%81%AE%E4%BD%9C%E6%88%90mac%E7%B7%A8)時、あまり余計なものをインストールしすぎると、トラブル発生時にリカバリーしても「リカバリーのインストール済みのパッケージが問題を起こしていた」ことで発見が遅れがちです。初回バックアップまで必要最低限に絞っておきます。</sup>

```shell-session
$ sudo apt install vim git
```

---

## 知っておくと便利なサバイバル術

その他の情報／切り分け用メモです。順不順で適宜アップデートしています。

### デフォルトのアカウントとパスワード

- ログインユーザー: `pi`
- パスワード: `raspberry`
- ホスト名: `raspberrypi.local` (`bonjour` による名前解決）

### ヘッドレス端末で描画したい。例えば KIOSK 端末の類い。でもデスクトップいらない。

> [SDL](https://ja.wikipedia.org/wiki/SDL)（`libsdl`）を活用できないか調べてみよう

ヘッドレスなの（モニタがないの）に描画したいというのも変なのですが、Raspbian Lite/RaspberryPi OS Lite の場合 X11（[X.org](https://ja.wikipedia.org/wiki/X.Org_Server)）やデスクトップ環境がインストールされていません。

そのため、モニタを HDMI 端子につなぐと [tty](https://ja.wikipedia.org/wiki/Tty) が 1 番でつながっているコンソール画面（CUI）が表示されています。

例えばアプリの実行状況を HDMI 接続のモニタで確認したい場合や[キオスク端末](https://ja.wikipedia.org/wiki/%E3%83%9E%E3%83%AB%E3%83%81%E3%83%A1%E3%83%87%E3%82%A3%E3%82%A2%E3%82%B9%E3%83%86%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3)などにも使いたい場合、ASCII 文字を駆使して CUI で表示しても良いのですが、GUI 環境が欲しいことがあります。

**つまり、ターミナル画面に画像を描画したい**のです。

一般的には OS を「Lite 版」でなく「デスクトップ版」を使い、OS 起動時にブラウザ（Chromium）を全画面表示で起動する方法が取られます。大半のプログラム言語は簡易 Web サーバーを持っており、HTML で GUI を組めるため色々と融通が効くからです。

しかし、簡単なものを描画するだけなのに GUI 関連にリソースを多く取られてしまいます。

CUI 画面とはいえ画面描画していることには変わりありません。そこで、自分でプログラムを組んで描画したい場合、自分のプログラム言語用に [SDL](https://ja.wikipedia.org/wiki/SDL)（`libsdl`、Simple DirectMedia Layer）のライブラリが使えるか確認してみましょう。

### ラズパイが生きているか LED で確認する

> `/boot/config.txt` の `[all]` セクションに `dtparam=act_led_trigger=heartbeat` を追加すると、動いている間は点滅し、ハングしていると点灯するようようになります。

他の Raspberry Pi と違い、ラズパイ Zero には基盤に LED は 1 つしか付いていません。デフォルトでは通電とディスクアクセスを示します。

しかし、ヘッドレスな場合、ラズパイが動いているかの確認が目視では難しくなります。

「（おまえ、生きてる？）」と、いささか不安になっただけなのにモニタをつなげたり、SSH 接続するのも面倒です。

SD カード作成時の `/boot` ディスク（パーティション）、もしくは `ssh` 接続で `/boot` ディレクトリにアクセスして `config.txt` の下部にある `[all]` セクションで LED のデフォルトの挙動を変更可能です。

`dtparam` の LED の挙動を設定するパラメーター `act_led_trigger` を `hearbeat` にする、つまり `dtparam=act_led_trigger=heartbeat` を追加すると、再起動後に「ピッピッ ... ... ピッピッ ...」と鼓動するように LED が点滅します。

これにより点灯していたら「（あ、ハングしてやがる）」と判断できます。（逆に視界にラズパイがあるとチカチカとウルサイのですが）

```ini:/boot/config.txtに追加
[all]
...
dtparam=act_led_trigger=heartbeat
```

### ラズパイの時刻情報を確認する

`timedatectl` コマンドでローカルの時間やタイムゾーンなどの確認が行えます。`System clock synchronized` が `no` の場合は、次項で NTP を設定する必要があります。

```shell-session
$ timedatectl
               Local time: 火 2021-12-28 15:32:12 JST
           Universal time: 火 2021-12-28 06:32:12 UTC
                 RTC time: n/a
                Time zone: Asia/Tokyo (JST, +0900)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no
```

### NTP（時刻の同期）を NICT にあわせる

Raspberry Pi 本体は**時刻を保存しておくための電池（`RTC`）を持っていません**。そのため、再起動するたびに時刻がリセットされるのですが、`systemd-timesyncd` デーモン（NTP サービス）が時刻を同期してくれます。

問題は「どの NTP サーバーと同期するか」です。デフォルトだと海外の Debian が運営する NTP サーバーと同期します。

`sudo systemctl status systemd-timesyncd | grep Status` で現在の NTP サービスの接続情報を確認し、シンクロ先（同期先）が `*.debian.pool.ntp.org` になっている場合は、NTP サーバーが海外のままです。

```shell-session:現在のNTPの同期先確認
$ sudo systemctl status systemd-timesyncd | grep Status
   Status: "Synchronized to time server for the first time 202.181.***.***:123 (2.debian.pool.ntp.org)."
```

放っておいてもいいのですが、同期が完了するまでの無駄なパケット送受信を避けるのと、ログの時刻を早めに正確にさせるためにも、物理的に近い（国内の） NTP サーバに設定することをオススメします。

- NTP:
    - `ntp.jst.mfeed.ad.jp ntp.nict.jp`
    - 国内 NTP サーバーとして [mfeed](https://www.mfeed.ad.jp/ntp/detail.html) と [NICT](https://jjy.nict.go.jp/tsp/PubNtp/index.html) を指定しています。有名だった [ntp.ring.gr.jp](http://www.ring.gr.jp/ring/ntp.html.ja) は動くのですが、サイトがメンテナンスされていないため除外しています。また、**自分のプロバイダーが NTP を用意している場合は、先頭に追加**します。
- FallbackNTP:
    - `time.cloudflare.com time.google.com 0.debian.pool.ntp.org 1.debian.pool.ntp.org 2.debian.pool.ntp.org 3.debian.pool.ntp.org`
   - 予備として [CloudFlare の日本の NTP](https://blog.cloudflare.com/ja-jp/secure-time-ja-jp/#--2) と [Google](https://developers.google.com/time) の NTP をデフォルトの前に追加しておきます。

設定は `/etc/systemd/timesyncd.conf` ファイルを `sudo` 権限付きで編集・追記後、設定を反映させて再起動してから、再度 NTP サーバーを確認します。（ワーニングが出る場合は次項を参照）

```diff:/etc/systemd/timesyncd.conf
   #  This file is part of systemd.
   #
   #  systemd is free software; you can redistribute it and/or modify it
   #  under the terms of the GNU Lesser General Public License as published by
   #  the Free Software Foundation; either version 2.1 of the License, or
   #  (at your option) any later version.
   #
   # Entries in this file show the compile time defaults.
   # You can change settings by editing this file.
   # Defaults can be restored by simply deleting this file.
   #
   # See timesyncd.conf(5) for details.
   
   [Time]
-  #NTP=
+  NTP=ntp.jst.mfeed.ad.jp ntp.nict.jp
-  #FallbackNTP=0.debian.pool.ntp.org 1.debian.pool.ntp.org 2.debian.pool.ntp.org 3.debian.pool.ntp.org
+  FallbackNTP=time.cloudflare.com time.google.com 0.debian.pool.ntp.org 1.debian.pool.ntp.org 2.debian.pool.ntp.org
   #RootDistanceMaxSec=5
   #PollIntervalMinSec=32
   #PollIntervalMaxSec=2048
```
```shell-session:
$ sudo timedatectl set-ntp true
$ sudo systemctl daemon-reload
$ sudo systemctl restart systemd-timesyncd.service
$ sudo reboot now
```

#### `Run 'systemctl daemon-reload' to reload units` が毎回表示される

NTP の接続状態を確認しようと `sudo systemctl status systemd-timesyncd` すると以下のワーニングが表示されます。

```bash
Warning: The unit file, source configuration file or drop-ins of
systemd-timesyncd.service changed on disk.
Run 'systemctl daemon-reload' to reload units.
```

しかし、サービスは起動しており、時刻も同期されています。

```shell-session:ログ
$ sudo systemctl status systemd-timesyncd
Warning: The unit file, source configuration file or drop-ins of systemd-timesyncd.service changed on disk. Run 'systemctl daemon-reload' to reload units.
● systemd-timesyncd.service - Network Time Synchronization
   Loaded: loaded (/lib/systemd/system/systemd-timesyncd.service; enabled; vendor preset: enabled)
  Drop-In: /usr/lib/systemd/system/systemd-timesyncd.service.d
           └─disable-with-time-daemon.conf
   Active: active (running) since Tue 2021-12-28 14:51:58 JST; 12min ago
     Docs: man:systemd-timesyncd.service(8)
 Main PID: 231 (systemd-timesyn)
   Status: "Synchronized to time server for the first time 210.173.160.27:123 (ntp.jst.mfeed.ad.jp)."
    Tasks: 2 (limit: 877)
   CGroup: /system.slice/systemd-timesyncd.service
           └─231 /lib/systemd/systemd-timesyncd

12月 28 14:51:55 my-rpi systemd[1]: Starting Network Time Synchronization...
12月 28 14:51:58 my-rpi systemd[1]: Started Network Time Synchronization.
12月 28 14:52:43 my-rpi systemd-timesyncd[231]: Synchronized to time server for the first time 210.173.160.27:123 (ntp.jst.mfeed.ad.jp).
```

これは、マシンが起動すると NTP サーバとの同期情報を `conf` ファイルに書き込むためで、初回の同期時に必ず表示されます。

ワーニングにもあるように `sudo systemctl daemon-reload` を実行すると表示されなくなるのですが、どうしても気になる場合は、`cron` の設定で再読み込みさせてもいいでしょう。

```conf:crontab
@reboot sleep 5 && systemctl daemon-reload && systemctl restart systemd-timesyncd 
```

### apt パッケージの自動更新

```bash
sudo apt-get update --yes
sudo apt-get install unattended-upgrades --yes
sudo dpkg-reconfigure -plow unattended-upgrades
```

上記は `apt` で `unattended-upgrades` パッケージをインストールして、`dpkg-reconfigure` で `unattended-upgrades` を割り当てます。

途中「自動的に安定版の更新をダウンロードしてインストールしますか?」と聞いてくるので、「はい」を選べば、`apt` の `update` や `upgrade` を定期実行できます。

<kbd>![スクリーンショット 2021-12-28 13.20.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78776/ea59194b-e746-17b5-b507-b889c6a78de1.png)</kbd>

:::note info
<sub><sup><strong>【自動アップデートによる新たな不具合について】</strong><br>他のラズパイの多目的な用途と異なり、ラズパイ Zero の場合は特定用途に特化した使い方をすることが多いと思います。そのため、<strong>一度、安定可動したら <code>upgrade</code> による新たな不具合を避けたい</strong>という気持ちが芽生えます。
しかし、安定性のため <code>apt upgrade</code> をしないのは、<code>ssh</code> どころか WiFi 接続すらしない「オフラインで動かす場合のみ」有効な手法です。
ヘッドレス用途の場合は WiFi や Bluetooth を有効にして常時起動しておくことが多いため、脆弱性を突かれて知らぬ間に乗っ取られていたりすることを避けるためにも、やはり定期的に <code>apt</code> の <code>update</code> と <code>upgrade</code> を行い不具合修正やセキュリティ・パッチを当てる必要があります。
オススメは、一度安定可動したら予備の SD カードに丸ごとバックアップして、いつでも入れ替えられるように<a href="https://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%BC%E3%83%AB%E3%83%89%E3%82%B9%E3%82%BF%E3%83%B3%E3%83%90%E3%82%A4" target="_blank">コールド・スタンバイ</a>（箱の裏などに予備の microSD カードをセロテープで止めおくなど）しておき、稼働中のものは常に最新のパッチが当たっているようにするのが長い目で見た場合に安全です。</sup></sub>
:::

- [unattended-upgrades](https://www.google.com/search?q=site:qiita.com+unattended-upgrades) の Qiita 記事 @ Google

### イメージ・ファイルのチェックサム確認方法

初回の OS インストール時に、<ruby>改竄<rt>かいざん</rt></ruby>されていないイメージを使うことは大事です。

改竄されていないかのチェックは、OS のダウンロード先のドメインの確認と、そこに添えてあるチェックサム値を使って確認します。

Raspberry Pi Imager を使う場合は、アプリがよしなにダウンロードしてくれるのですが、balenaEtcher など、自分で OS イメージをダウンロードして OS インストールする場合は、ある意味、チェックサムの確認は必須です。

#### チェックサムを目視で確認

`shasum` コマンドの `--algorithm` もしくは `-a` オプションで、ダウンロードしたイメージ・ファイルのチェックサムを算出して確認する。

```shell-session:ファイルのチェックサムを目視で比較確認（下記はSHA-256）
$ # --algorithm は -a でも可能
$ shasum --algorithm 256 ./2019-04-08-raspbian-stretch-lite.zip
```

`openssh` コマンドにパイプ渡しで、ダウンロードしたイメージ・ファイルのチェックサムを算出して確認する。

```shell-session
$ cat ./2019-04-08-raspbian-stretch-lite.zip | openssl sha256
```

#### 提供されたチェックサム・ファイルと比較して確認

`.zip` と同名の `.zip.sha1` もしくは `.zip.sha256` ファイルが提供されている場合は、`shasum --check` もしくは `shasum -c` コマンドで比較すると目視による確認より確実です。

```shell-session:*.zip.sha256ファイルも一緒にダウンロードして比較検証する例
$ shasum --check ./2019-04-08-raspbian-stretch-lite.zip.sha256
$ shasum -c ./2019-04-08-raspbian-stretch-lite.zip.sha256
2019-04-08-raspbian-stretch-lite.zip: OK
```

### `shutdown`／SD カードの取り出し時の注意

ラズパイから SD カードを抜く時は、必ず `sudo shutdown now` でシャットダウンし、LED ランプが消えてから抜きます。

> <sup>🐒 &nbsp; SD カードを挿し直しても USB 電源を抜き差し、つまり**電源の再投入をしないと起動しません**。抜き差し時、毎回チカラが入りすぎると USB 端子の接触不良を起こしかねないので注意します。

### SSH 接続で公開鍵を使う設定を行う

SSH 接続時にパスワード認証でなく、公開鍵・秘密鍵認証[^rsa]でログインさせる設定です。

公開鍵・秘密鍵のペアをまだ作成していない場合は、次項の「SSH 公開鍵・秘密鍵のペアを新規作成する」をご覧ください。

#### ローカルからリモートに転送する場合

1. `ssh-copy-id` コマンドでローカル[^local] の公開鍵（`id_rsa.pub`）をリモート[^remote] に転送する。

    ```shell-session
    $ ssh-copy-id -i ~/.ssh/id_rsa.pub pi@raspberrypi.local
    /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/Users/admin/.ssh/id_rsa.pub"
    /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
    /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
    pi@raspberrypi.local's password: 
    bash: warning: setlocale: LC_ALL: cannot change locale (ja_JP.UTF-8)
    
    Number of key(s) added:        1
    
    Now try logging into the machine, with:   "ssh pi@raspberrypi.local"
    and check to make sure that only the key(s) you wanted were added.
    ```

2. `$ ssh pi@raspberrypi.local` でパスワードなしでログインできるか確認する。<br>（エラーが出る場合、ローカルの `~/.ssh/known_hosts` に `raspberrypi.local` の古いログイン情報が残っていないか確認する。あった場合は削除する。）

#### SD カードなどに公開鍵をコピー済みの場合

1. 公開鍵の内容を、リモート先の `~/.ssh/authorized_keys` に追記します。

    ```bash:bootパーティションにある公開鍵をSSH接続用に追加する例
    cat /boot/id_rsa.pub >> ~/.ssh/authorized_keys
    ```
2. `~/.ssh` ディレクトリがない場合は作成し、追記後以下のパーミッションを設定します。
    - パーミッション
        - `chmod 0700 ~/.ssh`
        - `chmod 0600 ~/.ssh/authorized_keys`

[^local]: **ローカルとは** SSH 接続する側で、ここでは作業しているパソコンのことです。

[^remote]: **リモートとは** SSH 接続する先で、ここではラズパイのことです。

[^rsa]: **公開鍵・秘密鍵認証とは**、パスワードの変わりに「鍵」と呼ばれるデータを２つ使ったログイン方法です。<br><br>鍵には「鍵 A」と「鍵 B」の２つがあり、**片方の鍵で暗号化されたものは、もう片方の鍵でしか復号できないタイプの暗号方式**を言います。<br><br>つまり「鍵 A」で暗号化されたものは同じ「鍵 A」では復号できず、ペアとなる「鍵 B」でしか復元できません。また、その逆もしかりです。<br><br>この仕組みを利用して、片方の鍵を公開しておき、その鍵で暗号化してデータを送ってもらうことで安全な暗号通信が行えます。暗号化されたデータは、もう片方の鍵を持つものでなければ復号できないからです。<br><br>「鍵 A」と「鍵 B」は「親：子」の「１：１」の関係になっており、親の鍵から同じ子の鍵は作成できますが、子の鍵からは親の鍵は作れない仕組みになっています。つまり、親の鍵で暗号化したものは、「親の鍵」では復号できませんが、復号に必要な「子の鍵」は作れてしまうということです。<br><br>そのため、親の鍵を後生大事に保管しておき、子の鍵を適宜作成して公開するのが一般的であるため、**親となる鍵を「秘密鍵」、子となる鍵を「公開鍵」と呼びます**。<br><br>公開鍵・秘密鍵を使った認証は、リモート先（接続する相手の端末）に自分の「公開鍵」を登録しておくことで、パスワードを使わないログインを実現できます。具体的には、リモートとローカルの間で暗号化されたデータを送り合います。両者が送りあった暗号データがお互いに正しく復号されると、ローカルの「秘密鍵」とリモート先の「公開鍵」はペアである事が認められ、ログインできます。<br><br>また、より鍵を堅牢にするためにパスワードを設定することも可能です。具体的には、親の鍵（秘密鍵）を作成する際に設定する任意の文字列で、この時のパスワードを正しくは「パスフレーズ」と呼びます。これは、**パスワードは「共通鍵暗号」の「鍵」のことを指す**ため、公開鍵・秘密鍵暗号で秘密鍵を操作するために必要な文字（フレーズ）であることを明確にするためです。主に親の鍵（秘密鍵）で復号する時や、子の鍵（公開鍵）を作成する際に求められます。<br><br>この秘密鍵・公開鍵には、いくつかの種類と長さがあります。堅牢性、作成のしやすさ、相手との互換性を考えると、鍵の種類を `RSA` `ECDSA` `Ed25519` のいずれか、鍵の長さを 2048 ビット以上で作成するのが良いとされます。

### SSH 公開鍵・秘密鍵のペアを新規作成する

```bash:4096ビット長のRSA暗号鍵の作成例
$ ssh-keygen -t rsa -b 4096
```

- [「秘密鍵 作り方」の Qiita 記事](https://www.google.com/search?q=site:qiita.com+%E7%A7%98%E5%AF%86%E9%8D%B5+%E4%BD%9C%E3%82%8A%E6%96%B9) @ Google

### SSH 公開鍵の強度を確認する

- 鍵の長さが最低でも 2048 以上であることを確認する。
    - 推奨鍵長: 4096 bit、推奨鍵種: `Ed25519` `RSA` `ECDSA`

```bash
$ ssh-keygen -l -f ~/.ssh/id_rsa.pub
```

### SSH 接続のログイン制限（セキュリティ設定）

SSH 接続時 `root` ユーザーおよびパスワードによるログイン認証を無効にします。

1. リモート先で `/etc/ssh/sshd_config` ファイルを編集して以下の項目をコメントインして変更する。<br>（要 `sudo` 権限。`vi` が使いづらい場合は `$ sudo apt install vim` などで好きなエディタを入れておく）

```conf:/etc/ssh/sshd_config
#PermitRootLogin prohibit-password -> no
PermitRootLogin no
#PasswordAuthentication yes -> no
PasswordAuthentication no
```

IoT 的なものにも使うなら、念のため接続ポート先も 22 番から他のポートに変えておく。

```conf:/etc/ssh/sshd_config
#Port changed 22 -> 1234
Port 1234
```

この場合、`ssh` ログインする場合はポートを指定する必要があります。

```shell-session
$ ssh pi@mypizero.local:1234
```

### SD カードの初期化

ラズパイ用の SD カードは **SD Association 公式のツール「[SD Memory Card Formatter](https://www.sdcard.org/jp/downloads/formatter/index.html)」を使って初期化するのが確実＆楽**です。`boot` パーティションは FAT32、データ領域の本体パーティションは Linux Ext4 でフォーマットしないといけないからです。

- [SD Memory Card Formatter について](https://qiita.com/KEINOS/items/b1762a00169ecdfed8c0) @ Qiita
- 参考文献: [FAT32Pi: Windows PC と Raspberry Pi でSDカードを共用](https://qiita.com/UedaTakeyuki/items/1b9708cd40d5f83d4b7c) @ Qiita

### SD カードのバックアップ/リカバリーイメージの作成（Mac編）

一連の設定ができて、SSH 接続も問題ないようだったら **Etcher で一発リカバリーできるようにバックアップをお勧め**します。

<img width="100%" alt="スクリーンショット 2019-09-24 15.05.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78776/4b0b2bbe-7f10-c588-b9c0-193400f2ac8f.png">

1. ラズパイ上で `sudo apt-get clean` で余計なキャッシュを削除してから、シャットダウンして microSD カードを取り出す。
1. microSD カードを Mac にマウントする。（Finder で `boot` がマウントされたことを確認）
2. ディスクユーティリティを開き、マウントされた **`boot` の１階層上の親のディスク**（おそらくSDカードドライブ）を左列で選んで右クリック。（`boot` を選ばないこと）
3. ["[SDカードリーダー名]"からイメージ作成] を選択する。
4. 保存先を選び、以下の設定で「保存」する（要 Mac の管理者パスワード）

    | 項目名 | 設定内容 |
   | :--- | :--- |
   | 名前 | わかりやすい任意の名前 |
   | タグ | 空でOK |
   | フォーマット | CD/DVD マスター |
   | 暗号化 | なし |

5. 作成されたバックアップ/リカバリーイメージの拡張子を `.cdr` から `.iso` に変える。

以降は、`Etcher` で `.zip` ファイルを選んだ時と同じ手順で `.iso` を選んで復元できます。数分で簡単に復元できます！

注意点として、丸ごとイメージを作成するため SD カード内のデータが少なかったとしても SD カードと同じサイズのイメージが作成されます。バックアップのイメージサイズを小さくしたい場合は、以下の記事が参考になります。

- [Raspberry Piで最小サイズのバックアップを作成する](https://dev.classmethod.jp/hardware/raspberrypi-backup-restore/) @ Developers.IO

:::note warning
<sub><sup><strong>バックアップを実行してすぐに「キャンセルされました」と出た場合</strong>
Catalina 以降「ディスクユーティリティ」アプリにはディスク・アクセスに制限がかかっています。システム環境設定の「セキュリティとプライバシー」からプライバシーの設定で「フルディスクアクセス」に「ディスクユーティリティ」を追加します。</sup></sub>
:::

![スクリーンショット 2021-10-31 1.28.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78776/98118a2d-0095-3604-f5f6-1f5969ccf223.png)

### SD カードの不具合確認

Etcher でイメージを書き込んで "Success" とポップアップされるも、メイン画面で "Mismatch checksum" エラーが発生している場合、SD カードに問題が発生しています。書き込みは無事終了したものの読み込みに失敗しているため、SD カードの初期不良である可能性があります。

以下の SD カードのセクタをチェックするコマンド（書き込みと読み込みの確認コマンド）で SD カードを検証できます。

- SDカードチェッカー
  - Windows: `H2testw`
  - macOS: `f3` (`brew`[^brew] でインストール可能です。`$ brew install f3`）
  - Debian: `badblocks`（[badblocks](https://manpages.debian.org/buster/manpages-ja/badblocks.8.ja.html) は Debian 系標準コマンド）
- 参考文献
  - Issue 2894 "[Popup window says successful completion, main window says mismatched checksum](https://github.com/balena-io/etcher/issues/2894)" | balena-io/etcher @ GitHub
  - [怪しいSD Cardのチェックにはbadblocksコマンド(Debian Stretch Lite標準)が便利](https://qiita.com/KEINOS/items/43394e4bd3c8fcfb5ee8#%E6%80%AA%E3%81%97%E3%81%84sd-card%E3%81%AE%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF%E3%81%AB%E3%81%AFbadblocks%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89debian-stretch-lite%E6%A8%99%E6%BA%96%E3%81%8C%E4%BE%BF%E5%88%A9) @ コメント

[^brew]: **brewとは** macOS/Linux のパッケージマネージャーです。`brew` をインストールすると、コマンドラインからアプリ／プログラムなどのインストール・削除・アップデートなどの管理が行えます。

### `LC_ALL: cannot change locale (ja_JP.UTF-8)` が表示される場合

WiFi 設定時の `wpa_supplicant.conf` に `country=JP` と設定しているため、ロケールを日本語の `ja_JP.UTF-8` に変更しようとしているのですが、`Stretch Lite` `Buster Lite` には軽量化のためデフォルトで日本語設定が入っていません。

そのため、アップデート時などロケールの切り替えができない場合に、`/bin/bash: warning: setlocale: LC_ALL: cannot change locale (ja_JP.UTF-8)` が表示されます。

`sudo raspiconfig` で設定アプリを起動し、ロケールの言語を日本語に設定します。

### SSH 接続時「WARNING: POSSIBLE DNS SPOOFING DETECTED」と表示される場合

以前に `pi@raspberrypi.local` もしくは同じ IP アドレスの**別の端末に接続した可能性**があります。ローカルの `.ssh` ディレクトリにある `known_hosts` ファイルに接続履歴があるので、該当する行を削除しましょう。 （`~/.ssh/known_hosts`）

### スワップ領域の増やし方

RaspbianOS の**デフォルトのスワップ・ファイルのサイズは 100 MB** です。つまり、メモリ不足時にディスクで補えるサイズが 100 MB しかないということです。

そのため、メモリ不足でビルドやコンパイルに失敗することがちょくちょくあります。

`/etc/dphys-swapfile` のファイルの `CONF_SWAPSIZE` の設定を書き換えることでスワップ・ファイルのサイズを増やすことができます。（数値の値は メガバイトです。1GB にしたい場合は、`CONF_SWAPSIZE=1024` にします。Docker などを使う可能性がある場合は 2GB（2048MB) 程度確保しておくといいかもしれません）

```shell-session
$ # 変更
$ sudo vi /etc/dphys-swapfile
...
# CONF_SWAPSIZE=100 -> 1024
CONF_SWAPSIZE=1024
...
$ # 反映
sudo /etc/init.d/dphys-swapfile restart
...
$ # 以下でも反映可能
sudo dphys-swapfile swapoff && sudo dphys-swapfile swapon
...
$ # 確認（SIZE=メガバイト）
$ swapon -s
Filename            Type       Size     Used    Priority
/var/swap           file     102396        0          -2
$ # 念のための再起動
$ sudo reboot now
```

- <font color=red>**注意点**</font>
  - スワップ・ファイルはあらかじめ領域を確保してしまうので、そのぶん `/` の空き容量が減ることを忘れないでください。
  - 最大スワップサイズは 2048 MB（２GB）です。

### ディスクの空き容量確認

```bash
$ df -h
ファイルシステム   サイズ   使用  残り  使用% マウント位置
/dev/root         28G  2.0G   25G    8% /
devtmpfs         213M     0  213M    0% /dev
tmpfs            217M     0  217M    0% /dev/shm
tmpfs            217M  5.8M  211M    3% /run
tmpfs            5.0M  4.0K  5.0M    1% /run/lock
tmpfs            217M     0  217M    0% /sys/fs/cgroup
/dev/mmcblk0p1   253M   40M  213M   16% /boot
tmpfs             44M     0   44M    0% /run/user/1000
```

### `apt` が遅い



- `apt` のサーバーを日本国内のミラーサーバーに変更
    - `http://raspbian.raspberrypi.org` → `http://ftp.jaist.ac.jp` に変更する例

    ```diff:/etc/apt/sources.list
    - deb http://raspbian.raspberrypi.org/raspbian/ buster main contrib non-free rpi
    + deb http://ftp.jaist.ac.jp/raspbian buster main contrib non-free rpi
    ```

    - ミラーサーバー一覧: https://www.raspbian.org/RaspbianMirrors

- `apt` 利用時 IP v6 を無効にする

    ```bash:/etc/apt/apt.conf.d/99force-ipv4の作成
    $ echo 'Acquire::ForceIPv4 "true";' | sudo tee /etc/apt/apt.conf.d/99force-ipv4
    ```

- 参考文献： [Raspberry Pi3B+をキオスクモードで使う (2019年11月版)](https://qiita.com/yyano/items/81da0f56be1f5fe32781#apt) @ Qiita

### セキュリティ関連参考資料

- [初心者向！Raspberry Pi 最低限のセキュリティ設定【所要時間 30分】](https://qiita.com/mochifuture/items/00ca8cdf74c170e3e6c6) @ Qiita
- [ラズパイでやらなければいけない４つのセキュリティ対策！](https://qiita.com/nokonoko_1203/items/94a888444d5019f23a11) @ Qiita

## 検証環境＆動作実績

- macOS Mojave (OSX 10.14.6) / MacBookPro 13inch, Early 2015
- SD カードライター: Digio2 CRW-38M56BK （ナカバヤシ株式会社）
- <font color=red>失敗した SD カード</font>（初期不良、ラズパイゼロのセット同梱品）
    - 32 GB microSDHC UHS-I Card/CLASS10, U1, A1 (SanDisk Ultra)
    - 製品型番: SDSQUAR-032G-GN6MN @ [SanDisk](https://www.sandisk.co.jp/home/memory-cards/microsd-cards/ultra-microsd#specifications-section)
- <font color=blue>成功した SD カード</font>（コンビニで購入）
    -  32GB microSDHC CLASS 10 FAT32 (HIDISC)
    -  製品型番: HDMCSDH32GCL10UIJP-WOA @ www.mag-labo.com

```shellsession:動作実績RaspberryPiZeroW情報
pi@raspberrypi:~ $ date -R
Sun, 22 Sep 2019 14:07:06 +0100

pi@raspberrypi:~ $ uname -a
Linux raspberrypi 4.19.57+ #1244 Thu Jul 4 18:42:50 BST 2019 armv6l GNU/Linux

pi@raspberrypi:~ $ cat /etc/os-release
PRETTY_NAME="Raspbian GNU/Linux 10 (buster)"
NAME="Raspbian GNU/Linux"
VERSION_ID="10"
VERSION="10 (buster)"
VERSION_CODENAME=buster
ID=raspbian
ID_LIKE=debian
HOME_URL="http://www.raspbian.org/"
SUPPORT_URL="http://www.raspbian.org/RaspbianForums"
BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"

pi@raspberrypi:~ $ cat /proc/cpuinfo
processor	: 0
model name	: ARMv6-compatible processor rev 7 (v6l)
BogoMIPS	: 697.95
Features	: half thumb fastmult vfp edsp java tls 
CPU implementer	: 0x41
CPU architecture: 7
CPU variant	: 0x0
CPU part	: 0xb76
CPU revision	: 7

Hardware	: BCM2835
Revision	: 9000c1
Serial		: XXXXXXXXXXXXXX

pi@raspberrypi:~ $ rev=$(awk '/^Revision/ { print $3 }' /proc/cpuinfo) && curl -L perturb.org/rpi?rev=$rev
Revision : 9000c1
Model    : Zero W
Memory   : 512 MB
Overvolt : No
Released : Q1 2017
Notes    : (Mfg by Sony)
```