はじめに
この記事では, Raspberry Piを使って, 簡単なアクセスポイントとWebサーバーを構築していきます.
hostapd・dnsmasq・dhcpcdを使用してRaspberry Piをアクセスポイント化し, Flaskアプリケーションを自動起動する方法を解説します.
また, 今回はRaspberry Pi OS Liteを使用し, ディスプレイやキーボードを接続せず, すべての作業をSSHを使ってリモートで行います.
使用機材
- Raspberry Pi 4-B (OS: Lite 64bit)
- Mac Book Air
- LANケーブル
環境構築
環境構築をしていきます.
準備
今回は, Macを使ってRaspberry Piに有線接続してSSHしているので, 不要な方はこの工程を省いて大丈夫です.
まず, MacとRaspberry Piを有線LANケーブルで接続します.
システム設定 -> ネットワークから該当するインターフェースを選び, 以下のように静的IPアドレスを指定します.
SSHをします.
ssh pi@raspberrypi.local
これでモニターとキーボードを使わずに, 作業することが出来ます.
必要なパッケージのインストール
基本的に/home/pi上で作業します.
以下のコマンドを実行して必要なパッケージをインストールします.
sudo apt-get update
sudo apt-get -y install hostapd dnsmasq dhcpcd5
sudo apt-get -y install python3-pip
vimをインストールしますが, エディタはお好みのものをお使いください.
vimを使わない方は, これ以降vimをお使いのエディタに読み替えてください.
sudo apt-get -y install vim
Pythonの仮想環境構築とFlaskのインストール
仮想環境はvenvを使用していきます.
python -m venv .venv
以下で仮想環境有効化.
source /home/pi/.venv/bin/activate
Flaskをインストールします.
pip install Flask
NetworkManagerの無効化
アクセスポイント化したときに競合を避けるため, NetworkManagerを無効化します.
sudo systemctl disable NetworkManager
Pythonスクリプト
今回は, Flaskアプリケーションのコードはapp.pyに書きます.
また, アクセスポイントを立ち上げ, app.pyを呼び出すコードはmain.pyに書いていきます.
app.py (Flaskアプリケーション)
ここでは, Flaskアプリケーションを最小構成にします.
h1タグのHello, World!を返します.
main.pyでこのファイルをimportするので, app.run()をstart関数内に書きます.
host="0.0.0.0"は, Flaskが任意のIPアドレスでリクエストを受け付けます. ポートは, Webアプリケーションのテストに使われる8080を使用しました.
使用するポートの競合に注意してください.
from flask import Flask
app = Flask(__name__)
@app.route("/")
def index():
return "<h1>Hello, World!</h1>"
def start():
app.run(host="0.0.0.0", port=8080)
main.py (アクセスポイント)
subprocessというコマンドをimportします.
また, 先ほど作ったapp.pyも同じくimportします.
ssidの値は, RaspberryPiAccessPointにしました. また, パスワードは1234ABCDとしました. これらは任意のもので大丈夫です.
ap_configでは, Wi-Fiインターフェースとしてwlan0を指定しています.
アクセスポイント用に使用するLinuxのWi-Fiドライバnl80211を指定, hw_mode=aで5GHz帯をWi-Fiの動作モードとして指定, Wi-Fiのチャンネルは, 5GHzの36チャンネルを指定しています.
import subprocess
import app
def start_access_point():
ssid = "RaspberryPiAccessPoint"
password = "1234ABCD"
ap_config = f"""interface=wlan0
driver=nl80211
ssid={ssid}
hw_mode=a
channel=36
ieee80211n=1
ieee80211ac=1
wmm_enabled=0
macaddr_acl=0
auth_algs=1
ignore_broadcast_ssid=0
wpa=2
wpa_passphrase={password}
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP
rsn_pairwise=CCMP
"""
先程の設定をhostapd.confに書き込んでいきます.
3つ目のwith openの箇所では, hostapdが使用する設定ファイルを指定しています.
def start_access_point():
(省略)
with open("/etc/hostapd/hostapd.conf", "w") as f:
f.write(ap_config)
hostapd_default = "/etc/default/hostapd"
with open(hostapd_default, "r") as f:
content = f.read()
with open(hostapd_default, "w") as f:
content = content.replace("#DAEMON_CONF=\"\"", f'DAEMON_CONF="/etc/hostapd/hostapd.conf"')
f.write(content)
dhcpcd(DHCP Client Daemon)は, ネットワークインターフェースにIPアドレスを割り当てる役割があります.
今回は, Macを使ってRaspberry Piに有線接続してSSHしているので, 不要な方はeth0のコードは省いて大丈夫です.
eth0とwlan0に静的IPアドレスを設定し, Raspberry Piをアクセスポイントとして動作させる準備を行っていきます.
eth0にはMac側から手動でIPアドレスを192.168.1.1に指定したのでそれに合わせています. サブネットマスクは/24です. デフォルトゲートウェイとして192.168.1.1を指定し, DNSサーバーを192.168.1.1に指定しています.
wlan0には, 192.168.0.50を静的アドレスとして割り当ててます(サブネットマスクは/24). nohook wpa_supplicantは, WPA Supplicantを無効化しています.
def start_access_point():
(省略)
eth0_config = """\ninterface eth0
static ip_address=192.168.1.1/24
static routers=192.168.1.1
static domain_name_servers=192.168.1.1
"""
wlan0_config = """\ninterface wlan0
static ip_address=192.168.0.50/24
nohook wpa_supplicant
"""
with open("/etc/dhcpcd.conf", "w") as f:
f.write(eth0_config)
f.write(wlan0_config)
dnsmasqは, DNSサーバーの役割と自動的にIPアドレスを割り当てる役割があります.
192.168.0.50をDNSリクエストのlisten-addressとして指定します.
server=8.8.8.8はGoogleのパブリックDNSを上流のDNSサーバーとして指定します.
dhcp-range=192.168.0.50,192.168.0.70,12hでは, DHCPで割り当てるIPアドレスの範囲を指定します.
192.168.0.50から192.168.0.70の間で, リース期間は12時間です.
def start_access_point():
(省略)
dnsmasq_config = """
interface=wlan0
listen-address=192.168.0.50
server=8.8.8.8
domain-needed
bogus-priv
dhcp-range=192.168.0.50,192.168.0.70,12h
"""
with open("/etc/dnsmasq.conf", "w") as f:
f.write(dnsmasq_config)
hostapd, dnsmasq, dhcpcdを起動していきます.
最後に, mainでアクセスポイントの関数を呼び出した後, Flaskアプリケーションを起動しています.
def start_access_point():
(省略)
subprocess.call(["sudo", "systemctl", "unmask", "hostapd"])
subprocess.call(["sudo", "systemctl", "unmask", "dhcpcd"])
subprocess.call(["sudo", "systemctl", "enable", "hostapd"])
subprocess.call(["sudo", "systemctl", "enable", "dhcpcd"])
subprocess.call(["sudo", "systemctl", "start", "hostapd"])
subprocess.call(["sudo", "systemctl", "enable", "dnsmasq"])
subprocess.call(["sudo", "systemctl", "restart", "dhcpcd"])
subprocess.call(["sudo", "systemctl", "restart", "dnsmasq"])
subprocess.call(["sudo", "systemctl", "restart", "hostapd"])
if __name__ == "__main__":
start_access_point()
app.start()
これで, アクセスポイントを立てる -> Flaskアプリケーションを起動するというところまで完成しました.
全コードはGitHubにあげています.
自動起動設定(systemd)
systemdを使って, 自動起動させていきます.
以下のようにserviceファイルを作ります.
sudo vim /etc/systemd/system/web_server.service
以下の内容を記入していきます.
ポイントは.venvのPythonを起動しているところです.
[Unit]
Description=start access point and start web server
After=network.target
[Service]
ExecStart=/home/pi/.venv/bin/python /home/pi/main.py
WorkingDirectory=/home/pi
[Install]
WantedBy=multi-user.target
最後に, 自動起動を有効化します.
sudo systemctl enable web_server
動かしてみる
それでは動かしてみましょう.
自動起動するか確かめたいので, 再起動します.
sudo reboot
そして, http://192.168.0.50:8080 に入り, 以下のような画面になれば成功です!
おわりに
今回は, あるプロジェクトの中でこの記事の内容を実装する機会があったので, 復習と整理のためにこの記事を書いてみました.
Raspberry Piやネットワークについて理解が深まりました.
参考文献

