RaspberryPi
raspbian
Jessie
AK-020

Raspberry Piを3GネットワークPPP接続のみで運用(ロケットモバイル月298円定額)

More than 1 year has passed since last update.

データ通信用SIM(3G SIM)って、ちゃんと選べば月300円ぐらいのものもあって、すごく安くなりましたよね。こうなったら、Wi-Fiの代わりに3G SIMで常時接続しちゃっても、問題ないですよね?

ということで、Raspberry Pi A+ や Raspberry Pi Zero に USB接続の3Gモデムを繋いで、インターネットと常に接続されているマシンを作ります。

他のQiitaにある同様の3Gモデム接続設定と比べた新規性:

  • wvdial というダイアラーを使う作例が多いですが、今回 pppconfig を使った時の不具合と解消方法が判明したので、Linuxで一般的な標準パッケージ ppp に含まれている、古式ゆかしい pon poff によるPPP接続をします。
  • 作例で利用が多い、SORACOM Airって値段高くないですか……Raspberry PiはSSLを喋れるんだから、SORACOMの付加機能の SORACOM Beam とか使わずに安い定額SIMでいいんじゃないですか……

ざっくり概要

設定とか入る前にざっくりした説明しておきます

なにができるの?

これができます

Raspbery Pi ZeroとAKA-020の悪魔合体

  • Raspberry PiにUSB-3Gモデムを挿すと、docomoの電波で自動的にインターネットにつながります。
    • \プラグアンドプレイ!/
      • ↑「プラグアンドプレイ」って今日日聞かねえな
    • スタバでRaspberry Pi使った開発が捗る
      • ↑スタバで仕事しているふりの人ってほんとに捗っているんですかね……
        • ↑五反田のスタバはLet'snoteのが多い
          • ↑法人用Let'snoteの修理は大阪なのでアキバの例の場所じゃ直せないこれ豆な
  • Raspberry PiにUSB-3Gモデムを挿したまま電源が投入されると、自動でインターネットにリンクアップします。
    • Raspberry PiがIoT機器になるよ!
      • ↑リソースリッチなIoT機器だなおい
    • SSL/TLS通信まで平気で使える
      • ↑来いやNSA
    • AWS IoTがサンプルプログラムのまま使える
      • ↑プログラマが怠惰になるよ! 怠惰 is 美徳
    • リモートで遠隔地設置の Raspberry Pi のプログラムまで直せちゃう
      • ↑べんりやないの……

できないこと

  • スタバでネットサーフィン
    • ↑「ネットサーフィン」って今日日聞かねえな
    • HDMIモニタもスタバに持ち込もう
      • ↑スタバのない地域だってあるんですよ!
        • ↑サーセン
  • docomoの電波がないところで接続
    • ↑そんな地域あるんかな
      • ↑あるんだなこれが
        • ↑出張で行かされた(泣)
          • ↑サーセン
    • ↑docomoがないならWi-Fi使えばいいじゃない
      • ↑だからRaspberry PiはWi-Fi無モデルのが多い
        • ↑つことはUSBドングルだけでネットに繋がるの? ステキやん
  • USB挿したら音が出る
    • ↑スピーカーさえあれば
      • ピ↑ボ↓
        • ↑おっさん乙
  • Raspberry PiでモバイルHTTPサーバ
    • ↑3G SIMで払い出されるIPがプライベートIPだったり
      • ↑RasPiから外部ホストへトンネル掘れているってことは、あとはわかるよな?
        • ↑その外部ホストとやらでHTTPサービスしたほうが早いのでは?

ていうかんじです。

動作確認は?

今回のテストにあたり、

  • Raspberry Pi A+ 256MB
  • Raspberry Pi A+ 512MB
  • Raspberry Pi Zero カメラ端子なし版
  • Raspberry Pi Zero カメラ端子あり版
  • Raspberry Pi 3 B+

にNOOBSでインストールした Raspbian Jessie(2016-05-27)で動作確認をしております。

必要3G-USBモデム・3G SIM

  • 3G-USBモデムは ABIT AK-020(¥6000)
  • 3G SIM は ロケットモバイル神プラン(¥298/月)

を使います。

3G SIMに関しては、自分が調達できるものに合わせて適宜読み替えてください。

Raspberry Piのシステムファイルには、機材固有の設定をします。今回はロケットモバイル/AK-020専用設定となります。

つくるまえに

  • 本稿では、Raspberry Piがインターネットに接続可能になっている状態からセットアップしていきますので、Raspberry PiにRaspbian Jessieをセットアップする作業Raspberry Pi を有線もしくはWi-Fiでインターネットにつなぐ作業は予め完了しておいてください
  • 説明の際、 pi@raspberrypi:~ $ と書いている場所は、コンソールが表示するプロンプトですので、入力しないでください。
  • RaspberryPiのコンソールへコピペ と書いているところは、ブラウザ上でクリップボードにコピーしておいて、コンソール上にペーストするとファイルが生成されたりコマンドが実行されるようになっています。最後の行は改行がコピーできていないので、自分でEnterキーを入れてあげてください。

設定

実際に操作を順番に追って設定していきます。

① Raspbianにpiユーザでログイン

以下の方法のいずれかで、Raspberry Piへコンソールアクセスします。

  • Raspberry PiのGUIで、LXTerminal を起動
  • Raspberry PiをDHCP制御下の有線LANにつないで、他のホストからSSH接続して pi ユーザーでログイン
  • Raspberry PiでWi-Fiを使えるようにして、無線LANのネットワークに参加させ、ネットワーク内の他のホストからSSH接続して pi ユーザーでログイン
  • Raspberry PiのGPIOに出ているUARTにシリアル接続

② 3G-USBモデム AK-020を挿入した時のLinuxの挙動を調整

先人達の努力により、

  • 3G-USBモデムを接続すると最初はCDとして認識され、 Eject すると本来の通信デバイスとして認識される
  • Linux側でUSBの認識制御をする usb_modeswitch があって、特定のUSBデバイスが認識されたら eject するまでできちゃう
  • udev により、デバイスの認識とそれに対するふるまいを設定できる
  • Systemd と統合されているためデバイスの認識に合わせて、 Systemd へメッセージを送ることができる

ということがわかっています。

今回使用する3G-USBモデム、AK-020用の特別設定を準備します。

RaspberryPiのコンソールへコピペ
cat << 'EOS' | sudo tee /etc/udev/rules.d/40-ak-020.rules
ACTION=="add",\
  ATTRS{idVendor}=="15eb",\
  ATTRS{idProduct}=="a403",\
  RUN+="/usr/sbin/usb_modeswitch --std-eject --default-vendor 0x15eb --default-product 0xa403 --target-vendor 0x15eb --target-product 0x7d0e"

ACTION=="add",\
  ATTRS{idVendor}=="15eb",\
  ATTRS{idProduct}=="7d0e",\
  RUN+="/sbin/modprobe usbserial vendor=0x15eb product=0x7d0e"

ATTRS{../idVendor}=="15eb",\
  ATTRS{../idProduct}=="7d0e",\
  ATTRS{bNumEndpoints}=="03",\
  ATTRS{bInterfaceNumber}=="02",\
  SYMLINK+="ttyAK020",\
  ENV{SYSTEMD_WANTS}+="ifup@wwan0.service"
EOS
RaspberryPiのコンソールへコピペ
sudo reboot

これで、Raspberry PiのUSBポートにAK-020を差し込むと、

  • 最初に認識されるCD-ROMデバイスが自動でマウント解除され、
  • 次に認識されるUSBシリアルデバイスにドライバをあてがい、
  • USBシリアルデバイスを /dev/ttyAK020 にリンクします。
  • あと、(あれば)ネットワークインタフェース wwan0 をupします。

実際にAK-020をRaspberry Piにつなぐ前と、つないだ後で比較してみます。

udev調整後、AK-020未接続の/dev/tty*のリスト
$ ls /dev/tty*
/dev/tty    /dev/tty21  /dev/tty35  /dev/tty49  /dev/tty62
/dev/tty0   /dev/tty22  /dev/tty36  /dev/tty5   /dev/tty63
/dev/tty1   /dev/tty23  /dev/tty37  /dev/tty50  /dev/tty7
/dev/tty10  /dev/tty24  /dev/tty38  /dev/tty51  /dev/tty8
/dev/tty11  /dev/tty25  /dev/tty39  /dev/tty52  /dev/tty9
/dev/tty12  /dev/tty26  /dev/tty4   /dev/tty53  /dev/ttyAMA0
/dev/tty13  /dev/tty27  /dev/tty40  /dev/tty54  /dev/ttyS0
/dev/tty14  /dev/tty28  /dev/tty41  /dev/tty55  /dev/ttyprintk
/dev/tty15  /dev/tty29  /dev/tty42  /dev/tty56
/dev/tty16  /dev/tty3   /dev/tty43  /dev/tty57
/dev/tty17  /dev/tty30  /dev/tty44  /dev/tty58
/dev/tty18  /dev/tty31  /dev/tty45  /dev/tty59
/dev/tty19  /dev/tty32  /dev/tty46  /dev/tty6
/dev/tty2   /dev/tty33  /dev/tty47  /dev/tty60
/dev/tty20  /dev/tty34  /dev/tty48  /dev/tty61
udev調整後、AK-020接続後の/dev/tty*のリスト
 $ ls /dev/tty*
/dev/tty    /dev/tty21  /dev/tty35  /dev/tty49  /dev/tty62
/dev/tty0   /dev/tty22  /dev/tty36  /dev/tty5   /dev/tty63
/dev/tty1   /dev/tty23  /dev/tty37  /dev/tty50  /dev/tty7
/dev/tty10  /dev/tty24  /dev/tty38  /dev/tty51  /dev/tty8
/dev/tty11  /dev/tty25  /dev/tty39  /dev/tty52  /dev/tty9
/dev/tty12  /dev/tty26  /dev/tty4   /dev/tty53  /dev/ttyAK020
/dev/tty13  /dev/tty27  /dev/tty40  /dev/tty54  /dev/ttyAMA0
/dev/tty14  /dev/tty28  /dev/tty41  /dev/tty55  /dev/ttyS0
/dev/tty15  /dev/tty29  /dev/tty42  /dev/tty56  /dev/ttyUSB0
/dev/tty16  /dev/tty3   /dev/tty43  /dev/tty57  /dev/ttyUSB1
/dev/tty17  /dev/tty30  /dev/tty44  /dev/tty58  /dev/ttyUSB2
/dev/tty18  /dev/tty31  /dev/tty45  /dev/tty59  /dev/ttyUSB3
/dev/tty19  /dev/tty32  /dev/tty46  /dev/tty6   /dev/ttyprintk
/dev/tty2   /dev/tty33  /dev/tty47  /dev/tty60
/dev/tty20  /dev/tty34  /dev/tty48  /dev/tty61

後の工程で使うため、AK-020は接続したままにしておきます。

③ USB-3GモデムにAPN設定を入れる

今回利用したUSB-3Gモデム・AK-020は実質APN設定をUSB-3Gモデムに記憶させておく必要が無いです。なのでこの工程飛ばす

④ RaspbianにPPP設定を作る

ppp 設定用対話型プログラムの pppconfig をインストール。

RaspberryPiのコンソールへコピペ
sudo apt-get -y install pppconfig

pppconfig を起動する。これは、ロケットモバイルとAK-020用の接続設定となります。

RaspberryPiのコンソールへコピペ
sudo pppconfig rokemoba_ak-020

以下の設定を順番に設定する。モーダルインタフェースとなっているから、1項目ごとに入力していくので注意。

Configure Nameservers(DNS):Dynamic
Authentication Method:PAP
User Name:roke@moba
Password:rokemoba
Speed:460800
Pulse or Tone:Tone
Phone Number:*99#
Choose Modem Config Method:No
Manually Select Modem Port:/dev/ttyAK020

Finishedで設定ファイルの書き出しを行い、そのあと、Quitして終了。

Authentication Method(認証メソッド)ですが、pppconfig 2.3.18 のバージョンには、認証メソッドに CHAP を選んでも、パスワードが /etc/ppp/chap-secrets に記録されない不具合があるので1、認証メソッドを PAP にします。

PPP接続時、デフォルトルートをPPP側に置き換える設定

  • persist:接続維持
  • replacedefaultroute:PPP接続時にデフォルトルートを自動で置き換える設定。 実質的にこれによって3Gモデムでインターネット接続ができることになる。
RaspberryPiのコンソールへコピペ
cat << EOS | sudo tee -a /etc/ppp/peers/rokemoba_ak-020

persist
replacedefaultroute
EOS

書き換え後は以下のようになります。

/etc/ppp/peers/rokemoba_ak-020
# This optionfile was generated by pppconfig 2.3.18.
#
#
hide-password
noauth
connect "/usr/sbin/chat -v -f /etc/chatscripts/rokemoba_ak-020"
debug
/dev/ttyAK020
460800
defaultroute
noipdefault
user "roke@moba"
remotename rokemoba_ak-020
ipparam rokemoba_ak-020

usepeerdns
persist
replacedefaultroute

APN設定・PPP接続用チャットスクリプトの修正

PPP接続時に、モデムとコマンドシーケンスを送受信しますが、それの制御をするチャットスクリプトを調整します。

3G SIMのAPNの設定もこちらになります。

RaspberryPiのコンソールへコピペ
sudo sed -i -e "s/'' ATZ/'' ATH\n\
OK AT+CFUN=1\n\
OK ATZ\n\
OK 'ATQ0 V1 E1 S0=0 \&C1 \&D2'\n\
OK AT+CGDCONT=1,\"IP\",\"4gn.jp\"\
/" /etc/chatscripts/rokemoba_ak-020

書き換え後は以下のようになります。

/etc/chatscripts/rokemoba_ak-020
# This chatfile was generated by pppconfig 2.3.18.
# Please do not delete any of the comments.  Pppconfig needs them.
#
# ispauth CHAP
# abortstring
ABORT BUSY ABORT 'NO CARRIER' ABORT VOICE ABORT 'NO DIALTONE' ABORT 'NO DIAL TONE' ABORT 'NO ANSWER' ABORT DELAYED
# modeminit
'' ATH
OK AT+CFUN=1
OK ATZ
OK 'ATQ0 V1 E1 S0=0 &C1 &D2'
OK AT+CGDCONT=1,"IP","4gn.jp"
# ispnumber
OK-AT-OK "ATDT*99#"
# ispconnect
CONNECT \d\c
# prelogin

# ispname
# isppassword
# postlogin

# end of pppconfig stuff

⑤ PPP接続テスト

AK-020は接続したままにしてありますので、この状態でPPP接続のテストをします。

RaspberryPiのコンソールへコピペ
sudo pon rokemoba_ak-020

AK-020のランプが、接続後待機状態の緑点灯⇒赤点灯⇒緑点滅(2Hz)になると、PPP接続完了です。

RaspberryPiのコンソールへコピペ
curl inet-ip.info

で、ロケットモバイル(nuro)のホストIPが割りあげられていることを確認してください。

実行例
pi@raspberrypi:~ $ curl inet-ip.info
118.241.248.164
pi@raspberrypi:~ $ host `curl inet-ip.info`
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    16  100    16    0     0      9      0  0:00:01  0:00:01 --:--:--     9
164.248.241.118.in-addr.arpa domain name pointer mp76f1f8a4.ap.nuro.jp.
pi@raspberrypi:~ $

確認が終わったら、PPP接続を切断します。

RaspberryPiのコンソールへコピペ
sudo poff rokemoba_ak-020

3G-USBモデムのランプの緑点滅が、緑点灯になり、PPP接続が終了しました。

⑥ PPP接続用ネットワークインタフェースを作る

電源投入後、または3G-USBモデムをUSBポートに挿したタイミングで自動でPPP接続したいので、設定を作ります。

Raspberry Piに仮想のネットワークインタフェース wwan0 を用意し、PPP接続と紐づけます。

RaspberryPiのコンソールへコピペ
cat << 'EOS' | sudo tee -a /etc/network/interfaces

allow-hotplug wwan0
iface wwan0 inet ppp
    provider rokemoba_ak-020
EOS

書き換え後は以下の通り。

/etc/network/interfaces
# interfaces(5) file used by ifup(8) and ifdown(8)

# Please note that this file is written to be used with dhcpcd
# For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf'

# Include files from /etc/network/interfaces.d:
source-directory /etc/network/interfaces.d

auto lo
iface lo inet loopback

iface eth0 inet manual

allow-hotplug wlan0
iface wlan0 inet manual
    wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

allow-hotplug wlan1
iface wlan1 inet manual
    wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

allow-hotplug wwan0
iface wwan0 inet ppp
    provider rokemoba_ak-020

なお、Raspbian Jessieの Systemd では、/etc/network/interface に書かれたネットワークインタフェースは Systemd における .service タイプの Unit として認識されるようです。

⑦ ネットワークインタフェースのリンクアップテスト

ネットワークインタフェースがシステム上にブリングアップしてきたときにちゃんとPPP接続ができるかテストをしていきます。ケースは3通りです。

  • 手動でネットワークインタフェースを ifup してみる
  • 3G-USBモデムをUSBポートに挿入してみる
  • 3G-USBモデムをUSBポートに挿入したままRaspberry Piを再起動してみる

手動でネットワークインタフェースをifup/ifdownして接続テスト

wwan0 ネットワークインタフェースを ifup することで、PPP接続が開始します。

RaspberryPiのコンソールへコピペ
sudo ifup wwan0

3G-USBモデムの緑ランプが2Hz点滅するとPPP接続済み。

wwan0 ネットワークインタフェースを ifdown することで、PPP接続が終了します。

RaspberryPiのコンソールへコピペ
sudo ifdown wwan0

3G-USBモデムの緑ランプが点灯(待機状態)に切り替わります。

3G-USBモデムをUSBポートに挿入してリンクアップするかテスト

まだ3G-USBモデムがUSBポートに刺さったままだと思いますので、いったん抜きます。2

少し待ってから(10秒くらい)、もう一度USBポートに挿してみると、数十秒から2分ぐらいまでの間で自動で接続開始します(3G-USBモデムの緑ランプが2Hz点滅するとPPP接続済み)。

Raspberry Piを再起動して自動でリンクアップするかテスト

3G-USBモデムをUSBポートに挿した状態のままにして、Raspberry Piを再起動します。

RaspberryPiのコンソールへコピペ
sudo reboot

Raspberry Piブートアップの途中で、3G-USBモデムがリンクアップするはずです。

おめでとう! 君のRaspberry Piは3G回線という翼を得たのだ!

⑧ 一巻の終わり

PPP接続開始の時点で、デフォルトゲートウェイが3G側に切り替わり、Raspberry Piから外に出る接続は3G経由となりますが、3G SIMに割り当てられるIPアドレスがプライベートIPアドレスだったりします。

ということは、Raspberry Piの内部から外のインターネット側へは通信できますが、インターネット側からRaspberry Piの内部には入って行けません。そのような必要があるのなら、せっかくのLinuxなのですから、Raspbery PiからどこかのVPSなど自分所有ホストへSSHトンネルを掘るなどするとよいですね。

おまけ

この仕組み、なんに使おうかなー

Raspberry Piから外部ホストへSSHトンネルを掘る

3G-USBモデムだけが刺さったRaspberry Piに、別ホストからリモートログインできるようにするため、Raspberry Piから、3G-USBモデムを通じインターネット上のほかのホストにSSH接続し、トンネルを掘ります

遠隔地に置きっぱなしのRaspberry Piがあったとして、そのRaspberry Piが遠隔地から手元のホストにトンネルを自力で掘ってくれるので、自分が遠隔地に行かなくともRaspberry Pi側から掘られ済みのトンネルを通じてリモートログインできるのはとっても便利なような気がします。

見方を変えると、インターネットからRaspberry Piに入れるようになるUSBドングル、とも言えますね。

RaspberryPiのコンソールへコピペ
sudo apt-get -y install autossh
RaspberryPiのコンソールへコピペ
cat << "EOS" | sudo tee /etc/ppp/ip-up.d/10ssh-tunnel
#!/bin/sh

# This script is called with the following arguments:
#    Arg  Name                          Example
#    $1   Interface name                ppp0
#    $2   The tty                       /dev/ttyS1
#    $3   The link speed                38400
#    $4   Local IP number               12.34.56.78
#    $5   Peer  IP number               12.34.56.99
#    $6   Optional ``ipparam'' value    foo

if [ "$2" = "/dev/ttyL05A" \
  -o "$2" = "/dev/ttyAK020" \
]; then

    # ppp0 の txqueuelen が 3 なので、大きくする
    /sbin/ifconfig $1 txqueuelen 128

    # root権限で動いているため、ほかのユーザで実行したい場合は
    # su <user> -c "echo hoge" 的なことをする
    #
    # autossh でトンネルを掘る場合は、トンネルの出口の sshd の
    # 設定で、ClientAliveInterval 10/ ClientAliveCountMax 3
    # などの 回線が死んだらsshも自然に死ぬようにしておく必要が
    # あります(送り側のautosshでsshのセッションを張りなおしても、
    # 受け側の古いsshdが死なずに居座るとListen出来ないので)。

    su pi -c \
        '/usr/bin/autossh \
        -N -f -M 0 \
        -o ServerAliveInterval=60 \
        -o ServerAliveCountMax=3 \
        -o ExitOnForwardFailure=yes \
        -o StrictHostKeyChecking=no \
        -R 10022:localhost:22 \
        -i /home/pi/.ssh/id_rsa \
        -l remotehostuser \
        example.com'
fi

exit
EOS
RaspberryPiのコンソールへコピペ
sudo chmod 755 /etc/ppp/ip-up.d/10ssh-tunnel

/etc/ppp/ip-up.d/ の中に実行権限をつけたスクリプトを置いておくと、PPPで接続確立後に実行されますので、 autossh によるSSHトンネルを掘る例です。

これをすると、3G電波だけでインターネットにつながっている Raspberry Pi に外部ホストからリモートログインが実現できます。

SSHトンネルの出口となっている外部ホストのコンソールへコピペ
slogin pi@localhost -p 10022 -o StrictHostKeyChecking=no

応用

GPSを搭載して、node.js を使って AWS IoTJSON をPubして、 DynamoDB に現在位置をダダ記録するのはどうでしょう。

PasPiApuls-3GUSB-GPS.jpg

参考文献

脚注


  1. なお、PPP接続のための別のパッケージ wvdialCHAP 認証で設定すると、正しく /etc/ppp/chap-secrets にパスワードが設定されるため、以降 CHAP で設定していた pppconfig で作った接続設定でもつながるようになります。Raspbianでの接続例は wvdial での例ばかりなのはおそらくこれのせい。 

  2. 3G-USBモデムが通信中に、いきなりUSBポートから抜いても、PPP接続は正常にクローズ・終了処理されますが、通信路が急になくなるので、アプリケーションレベルで不具合が出ることがあります(TCP通信であれば、FINパケットなしで通信が途絶するので通信路クローズのタイミングは実装と設定による)。