背景
自宅では長らくAirMac Expressを愛用してきました。最初は部屋間にLANケーブルを這わせるのはどうしても嫌、という妻の要望を叶える為、WDSモードで部屋同士のネットワークを無線LANで繋げるために購入しましたが、その必要も無くなった後は、AirPlayのレシーバとして重宝していました。
ただ、「諸行無常の響きあり」とあるように、どんなものにも別れの時はあります。最初3台購入していたAirMac Expressも、購入して10年程経ってから、一つ、また一つ壊れていき、今ではついに残り一台となってしまいました。
無線LANのアクセスポイントとしての代替品は世の中にたくさんありますが、AirPlayのレシーバとしての代替品は寡聞にして知りません。いや、ある事はあるようなのですが、私のやりたい事は既存のスピーカと繋げて、Appleご謹製のRemoteで大元のiTunesを操作して、いつでも好きな音楽を枕元で聞くというものなので、そういう目的に見合う物がどうやら世の中には無いようなのです。
長くなりましたが、この文章は、残ったただ一つのAirMac Expressがお亡くなりになる前に代替品をなんとかして準備した手順の備忘録になります。
前提条件
- Raspberry Pi
- MicroSDカード
- HDMI接続のモニター
- USB接続のキーボード
- まぁまぁのLinuxの知識
おおまかな手順
何故か家にRaspberry Pi 3Bが一つ余っていたので、これを使ってAirMac Expressの代替品を作成する事にしました。ネットで検索すると、Raspberry PiをAirPlayのレシーバにしようとされた方々が多数いらっしゃったので、特に苦労する事も無いだろうと思ったのがその理由です。
- Raspberry Piのセットアップ
- Raspberry Pi OSの初期設定
- Raspberry Pi OSの追加設定
- Webminの導入
- AirPlayレシーバの設定
- apt経由での導入
- Dockerコンテナとしての導入
- Dockerの導入
- Portainerの導入
Raspberry Piのセットアップ
知らない間にRaspbianがRaspberry Pi OSと名前を変えていました。Raspberry Pi OSはOSイメージをダウンロードしてMicro SDカードに書き込む必要がありますが、この作業を超絶簡単に行ってくれるのがRaspberry Pi Imagerです。これはRaspberry Piの公式ページからダウンロードできました。作業する環境に合わせて、Windows/Mac/Linuxのどれかを選んでからダウンロードします。
もちろんMicroSDカードも必要です。今回は何故か家で余っていた16GBのMicro SDカードを使用する事にしました。
Raspberry Pi Imagerを立ち上げるとこのような画面が表示されます。Operating SystemからインストールするOSの種類を、Storageで書き込み先を選択します。
今回は出来るだけ余計な物をインストールしたくなかったので、Raspberry Pi OS Liteを選びました。Writeを押すと必要なイメージをダウンロードして指定したSDカードに書き込んでくれます。便利な世の中になったものです。
全ての作業が終了したら、もうSDカードを抜いてもいいよ、というメッセージが表示されるので、書き込みが終わったSDカードをRaspberry Piに差し込んで、ついでにモニター・キーボードも接続して電源ケーブルを接続します。何やら色々表示された後、ログインプロンプトが表示されるので、とりあえずデフォルトのユーザであるpiでログインします。パスワードはraspberryです。
Raspberry Pi OSの初期設定
Raspberry Pi OSを使うに当たって最小限必要と思われる設定を行っていきます。必要最小限の設定はraspi-config
で行う事が出来ます。
$ sudo raspi-config
日本語環境
まずは日本語環境に変更します。UTF-8をlocaleに追加。ただ、コマンドラインで作業する事もあるので、標準はCにしておきます。また、タイムゾーンは東京にします。今回使用したキーボードが109キーボードなので、それに一番近そうな設定にします。
Locale
-
Localisation Options
を選択 -
Locale
を選択 -
ja_JP.UTF-8
を追加 -
Default locale
ではC.UTF-8
を選択
タイムゾーン
-
Localisation Options
を選択 -
Timezone
を選択 -
Asia
を選択 -
Tokyo
を選択
キーボード
-
Localisation Options
を選択 -
Keyboard
を選択 -
Keyboard model
ではGeneric 105-Key PC (intl.)
を選択 -
Keyboard layout
ではOther
を、続くCountry of origin
ではJapanese
を選択 - もう一度
Keyboard layout
に戻るので、今回はJapanese
を選択 - AltGrに割り当てるキーには
The default for the keyboard layout
を選択 - Composeキーは
No Compose key
を選択
無線LAN
-
Localisation Options
を選択 -
WLAN Country
を選択 -
JP
を選択
sshを有効化
後ほどWebminを入れてwebベースで設定を行えるようにしますが、それでもコンソールで作業する場面も出てくると思うので、sshを有効化しておきます。
-
Interface Options
を選択 -
SSH
を選択 -
Yes
で有効化する
WiFiの有効化
WiFiでネットワークに接続する場合、下記のようにWiFiを有効化する必要があります。ただしこのままですと少し難があるので、後ほど説明するようにパスフレーズのハッシュ化を行った方が良いと思います。
-
System Options
を選択 -
Wireless Lan
を選択 - SSIDとパスフレーズを入力
ホスト名の変更
ホスト名の変更は以下のようにおこないます。
-
System Options
を選択 -
Hostname
を選択 - 変更したいホスト名を入力
画面サイズ
これはだいぶ余計かもですが、今回準備したモニターは持ち運び可能な小型モニターなので、高解像度のままだととても見にくいため、低解像度にしました。基本的にはリモートで作業を行う事になるので、高解像度にする必要も無いですし。
-
Display Options
を選択 -
Resolution
を選択 -
CEA Mode 1
を選択して解像度を640x480にしておく。
最後にFinish
を選択すると再起動するかを聞かれるので、Yes
で再起動します。特にホスト名を変更した場合再起動する必要があるので、もし途中でESCキーを押した等でraspi-config
を抜け出した場合は自力で再起動して下さい。
Raspberry Pi OSの追加設定
ファイアウォールの設定
apt
等でネットワークを使用する前に、まずはファイアウォールの設定を行っておきます。今の時代、たとえ個人で内向けに運用しているサービスでも攻撃を受ける可能性が十分にあります。1
ファイアウォールの設定には通常iptables
を使用しますが、正直難しいです。そこで、今回ファイアウォール設定を簡単に行えるufw
を導入してみます。コンソール上から下記のような手順でufw
のインストールから有効化までをおこないます。
$ sudo apt install ufw
$ sudo ufw enable
次に基本外から内への通信を遮断します。
$ sudo ufw default DENY
このあと最低限開いておきたいポートを指定します。今回sshを有効化しているので、とりあえずsshのポートだけ開こうと思います。ただし、万が一のため、同じLAN内からの接続のみを許可し、短時間で複数回接続を試みてきた通信を一時拒否するようにします。もし、同一LANが192.168.1.0/24であれば下記のようにします。
$ sudo ufw limit from 192.168.1.0/24 to any port ssh
ここから先はsshを使用してリモートで作業も可能です。
無線LANの追加設定
raspi-config
でWiFiの設定を行った場合、WiFiの接続設定ファイルにパスフレーズが平文で書き込まれてしまうので、あまり心情的に宜しくはありません。WiFiの接続設定は/etc/wpa_supplicant/wpa_supplicant.conf
に保存され、またパスフレーズのハッシュ化にはwpa_passphrase
が使用できます。
そこで気になる方は、下記のような手順でパスフレーズをハッシュ化してみて下さい。
まず下記のコマンドを実行して、ハッシュ化されたパスフレーズを含んだ設定をwpa_supplicant.conf
に保存します。
$ sudo sh -c "wpa_passphrase <SSID> <パスフレーズ> >> /etc/wpa_supplicant/wpa_supplicant.conf"
こうする事で下記のような行がwpa_supplicant.conf
に追加されているはずです。
network={
ssid="<SSID>"
#psk="<平文のパスフレーズ>"
psk=<ハッシュ化されたパスフレーズ>
}
上記から平文のパスフレーズの行を削除してください。また、raspi-config
によって書き込まれた下記のような行も上記の行の前にあると思うので、丸ごと削除してください。
network={
ssid="<SSID>"
psk="<平文のパスフレーズ>"
}
SWAP領域の停止
Raspberry Piは基本SDカードで運用するので、頻繁な書き込みにはあまり強く無いと思います。そのため、SWAP領域を無効化して少しでも寿命を伸ばそうと思います。
$ sudo swapoff --all
$ sudo systemctl stop dphys-swapfile
$ sudo systemctl disable dphys-swapfile
パッケージとファームウェアのアップグレード
これでいろいろ作業するための最低限の設定が終わりましたので、一度
パッケージとファームウェアのアップグレードを行っておきます。
$ sudo apt update
$ sudo apt full-upgrade
$ sudo apt-get autoremove
$ sudo apt-get autoclean
$ sudo reboot
Webminの導入
ここまでで基本的な設定は全て終了しましたが、今後リモートで色々と設定作業を行う際、ssh
で接続してというよりはWebベースで設定が行えると便利です。そんな環境を提供してくれるのがWebminです。Webminの導入も昔に比べるとだいぶ楽になりました。
まず、Webminが提供されているリポジトリのソース元をapt
のsources.list
に追加します。
$ sudo vi /etc/apt/sources.list
でsources.list
を開いて、下記のような行を追加します。
## webmin
deb https://download.webmin.com/download/repository sarge contrib
次に、上記リポジトリのパッケージを認証するためのキーを追加しまします。
$ wget https://download.webmin.com/jcameron-key.asc
$ sudo apt-key add jcameron-key.asc
$ rm jcameron-key.asc
また、上記リポジトリにはhttps経由で接続するので、https経由でaptが使用できるようapt-transport-https
もインストールします。
$ sudo apt install apt-transport-https
最後にWebminをインストールします。
$ sudo apt update
$ sudo apt install webmin
これでWebminに接続してWebベースで各種設定が行えるようになっています。Webminにはデフォルトでは下記のように10000番ポートを指定して接続します。
https://<接続先IP>:10000
そのため下記のように10000番ポートを開いておきます。
sudo ufw allow from 192.168.1.0/24 to any port 10000
なお、接続するポート番号はもちろん変更出来ます。その際には上記のufw
への指定も変更したポート番号に応じて変更して下さい。
Webmin上で新規ユーザ設定
せっかくWebminを導入してみたので、デフォルトの作業ユーザであるpiに代わるユーザを作成してみます。
なお、Webminで使用しているSSL証明書はいわゆるオレオレ証明書なので、接続した際に下記のように警告される筈です。まぁ、無視しても良いのですが、もし気になるようでしたらLet's EncryptからSSL証明書を入手しても良いかも知れません。
Webmin上ではSystemから選択できるUsers and Groupsでユーザ情報の管理が出来ます。Create a new user
ボタンを選択する事で新規ユーザを作成出来ます。新規ユーザ名とパスワードを入力し、シェルは/bin/bash
を選んでみます。所属グループはpiと同じ物を選択します。Create
ボタンでユーザ作成を終了し、新規ユーザでのログインに支障が無い事が確認出来たら、piユーザを無効化しておきます。
shairport-syncの導入
さて、そろそろ本題の、AirPlayのレシーバの設定をおこないます。ここからは大分試行錯誤が入ります。
aptを使用しての導入
AirPlayのレシーバとして使用するには、shairport-syncというソフトウェアを導入すると良いらしいです。shairport-syncはDebianのパッケージとしても提供されているので、早速apt
を使ってインストールしてみました。
$ sudo apt install shairport-sync
これで、RemoteのAirPlay一覧にRaspberry Piのホスト名が表示されますが、このままでは使用出来ません。
shairport-syncは外からの接続要求やデータのやりとりに特定のポートを使用しており、この設定は/etc/shairport-sync.con
に記述します。デフォルトでは以下のように、TCPの5000番と、UDPの6001-6101番を使用するようです。
general =
{
// port = 5000; // Listen for service requests on this port
// udp_port_base = 6001; // start allocating UDP ports from this port number when needed
// udp_port_range = 100; // look for free ports in this number of places, starting at the UDP port base. Allow at least 10, though only three are needed in a steady state.
}
shairport-syncが使用するポートを開くため、ufwで以下のように指定します。
$ sudo ufw allow from 192.168.1.0/24 to any port 5000 proto tcp
$ sudo ufw allow from 192.168.1.0/24 to any port 6001:6101 proto udp
これでAirPlayの接続先として選べます。なお、このままですと、人によっては音が出ずに悩むかも知れません。Raspberry Piは音声の出力先は2種類あり、一つは本体についているイヤフォンジャックから、もう一つはHDMI経由での出力になります。で、どうも標準ではHDMI経由の出力になっているようです。
$ amixer
Simple mixer control 'HDMI',0
Capabilities: pvolume pvolume-joined pswitch pswitch-joined
Playback channels: Mono
Limits: Playback -10239 - 400
Mono: Playback 0 [96%] [0.00dB] [on]
これを変えるには、例えばraspi-config
を立ち上げて、
-
System Options
を選択 -
Audio
を選択 -
1 Headphones
を選択してOK
を押す
とする事で標準の音声出力先をイヤフォンジャックに変更出来ます。変更後、例えば
$ aplay /usr/share/sounds/alsa/Front_Center.wav
とすると、どちらから音が出ているか直接確認出来ます。
ただ、この方法はshairport-sync
には反映されません。shairport-sync
では出力先は/etc/shairport-sync.conf
に記述する必要があります。
alsa =
{
// output_device = "default"; // the name of the alsa output device. Use "alsamixer" or "aplay" to find out the names of devices, mixers, etc.
}
で、上記output_device
とmixer_device
の記述方法ですが、ちゃんと書かれた文書が見つからなかったのですが、
$ man shairport-sync
によると、記述例として
alsa = {
output_device = "hw:0";
mixer_control_name = "PCM";
};
とあるので、多分、"hw:<カード番号>"
のように指定すればいいのではと推測しています。カード番号はaplay -l
で分かります。
$ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: b1 [bcm2835 HDMI 1], device 0: bcm2835 HDMI 1 [bcm2835 HDMI 1]
Subdevices: 4/4
Subdevice #0: subdevice #0
Subdevice #1: subdevice #1
Subdevice #2: subdevice #2
Subdevice #3: subdevice #3
card 1: Headphones [bcm2835 Headphones], device 0: bcm2835 Headphones [bcm2835 Headphones]
Subdevices: 4/4
Subdevice #0: subdevice #0
Subdevice #1: subdevice #1
Subdevice #2: subdevice #2
Subdevice #3: subdevice #3
これによるとイヤフォンジャックのカード番号は1なので、
alsa =
{
output_device = "hw:1";
}
として、
$ sudo systemctl restart shairport-sync
でサービスを再起動させます。これで、イヤフォンジャックから音楽が流れるようになっている筈です。
Dockerコンテナとしての導入
これでうまく行ったかと思ったら、そうは問屋が卸してくれませんでした。標準ではスピーカー名がホスト名になるので味気がありません。そこでスピーカー名を変えようと
general =
{
name = "AirPlay";
}
としてサービスを再起動させると、何故かエラーで落ちてしまいます。
$ sudo systemctl restart shairport-sync
Job for shairport-sync.service failed because a fatal signal was delivered to the control process.
See "systemctl status shairport-sync.service" and "journalctl -xe" for details.
理由がさっぱりわからなかったのですが、このサイトでも同様のエラーが報告されていて、作者による返事では理由がいまいちはっきりせず、とりあえず3.3.5以上にしてくれ、というものでした。apt
でとってきたのは3.2.2でした。
$ shairport-sync -V
3.2.2-OpenSSL-Avahi-ALSA-pa-dummy-stdout-pipe-soxr-convolution-metadata-sysconfdir:/etc
3.3.5以上にあげるには自分で最新版のソースコードを持ってきてbuildするか、Debianのbackportsとやらから持ってくるといいらしいのですが、前者は面倒だし、後者はいまいち不信感があるのであまりやりたくないです。どうしたものかと悩んでいたら、shairport-syncのDockerイメージがあることを発見。Dockerも導入しようかと思っていたところなので、渡に舟と、Dockerコンテナとしてshairport-syncを導入する事にしました。
その前にもったいないけど、まずインストール済みのshairport-syncと関連するパッケージを削除しました。
$ sudo apt purge shairport-sync
$ sudo apt autoremove
Dockerの導入
Dockerのサイトによると、Raspberry Pi OSへはDebianで通常推奨しているインストール方法は使用出来ないらしい。
Raspbian users cannot use this method!
For Raspbian, installing using the repository is not yet supported. You must instead use the convenience script.
そこで、ここに書かれている手順に沿って導入してみました。
まず、念の為、既存のDockerがらみのパッケージを全て削除して欲しいらしい。多分そんなものは一つも入っていない無い筈だけど、念の為下記のコマンドを実行。
sudo apt-get purge docker docker-engine docker.io runc
次にconvenienceなスクリプトをダウンロードします。
curl -fsSL https://get.docker.com -o get-docker.sh
ダウンロード後スクリプトを実行すると、勝手に必要なファイルのダウンロードとインストール作業を行ってくれます。
sudo sh get-docker.sh
Portainerの導入
追加でWebベースでDokerコンテナの管理が出来るようPortainerも導入します。PortainerはDockerイメージがあるので、
sudo docker pull portainer/portainer-ce:linux-arm
としてDockerイメージを入手しておいて、
sudo docker run -d -p 9000:9000 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:linux-arm
というように起動させます。この例ではポート9000番を使ってPortainerに接続するので、下記のように9000番を開けておきます。
sudo ufw allow from 192.168.1.0/24 to any port 9000
これで以下のようなURLでPortainerに接続できます。
https://<接続先IP>:9000
最初に接続した際に、管理者ユーザの作成が必要になります。これはPortainerだけで使用されるユーザのようです。
shairport-syncコンテナ
shairport-syncのDockerイメージはmikebrady/shairport-sync:latest
です。
PortinerのContainers
タブを選択して、コンテナ名を入力し、Dockerイメージにmikebrady/shairport-sync:latest
を指定してDeploy the container
ボタンを押すと、Dockerイメージのダウンロードからコンテナ起動までを行ってくれます。
他に指定すべきオプションはこちらの説明をみると、
- NetworkはHost
- Restart policyはUnless stopped
- Deviceに
/dev/snd
- その他、shairport-syncとALSAに渡す引数をCommandに指定する。
-
-a AirPlay
でスピーカー名を指定 -
-- -d hw:1
でイヤフォンジャックを出力先に指定
-
これで好みのスピーカ名で接続できるようになっています。
今後の予定
本当はAirMac Expressの本来の目的であるWiFiアクセスポイントとしての設定まで行いたかったのだけど、自宅ではブリッジモードでWiFiのアクセスポイントを作成したいのでbridge-utils
をインストールしてゴニョゴニョしましたが、結論として現在WiFi側とLAN側をブリッジさせる事は出来なくなっているらしい。とりあえずRaspberry Piに搭載されているWiFiを使用してブリッジは出来ないっぽい。
$ sudo brctl addif br0 wlan0
can't add wlan0 to bridge br0: Operation not supported
解決策としては、ここにあるように、無線LAN側を4addr(WDS)モードにするか、もしくは外付けUSBのWiFiアダプターを用いると良いようだ。ただ、前者は理由が完全に理解出来ていないし(WDSモードってイーサコンバータとして使う場合に使用するのではなかったのかな?)、後者は、余っている筈のWiFiアダプターが行方不明になってしまったので、とりあえず今後の課題としました。
また、イヤフォンジャック経由ですと音が悪いとのことでUSB-DACを使用すると良いという話もあるので、こちらも試してみようと思う。
その他参考にしたサイト
-
特にちょうど今Qlockerが話題になっていて他人事では無いです。 ↩