716 字 · 约 4 分钟阅读

目录
带有4G扩展板的树莓派零

如果你能用1瓦的功率运行一个博客,通过4G网络从太阳能供电的树莓派零上提供服务会怎样?

作为软件工程师,我们大部分时间都生活在一个拥有几乎无限云资源的世界里,硬性限制已经被弹性账单和一层又一层让我们远离硬件的抽象(IaaS、PaaS、SaaS)所取代。很容易忘记用很少的东西能做什么。

这是一个用更少做更多的实验。跟我一起踏上这段旅程。

这是一个2部分系列的第1部分。 第1部分(本文)涵盖使用Cloudflare隧道通过4G构建和提供博客。 第2部分将进一步离网:用太阳能板和电池扩展板为整个装置供电,让它在夜间持续运行,设置扩展板上的GPS模块,以及一些从树莓派挤出每一毫瓦的技巧。

前提条件

开始前的先决条件:

  • 一个添加到Cloudflare的域名(免费计划)——参见Cloudflare文档
  • 你机器上的SSH密钥对(~/.ssh/id_rsa)
  • 在本教程中,将<user>替换为你选择的用户名(例如thylong),将<hostname>替换为你选择的主机名(例如solar)

硬件

组件费用
树莓派零 2 W(推荐零2 W——它同时支持32位和64位系统;原始零W仅支持32位)18€
微雪电子SIM7600G-H 4G扩展板75€ 哎哟…
Micro-SD卡(最小8GB)+ MicroSD转SD适配器(用于从笔记本电脑烧录)5€
10W 5V太阳能板USB-C25€
Pi Sugar 3 Plus电池扩展板1200mAh——设置在第2部分中介绍34€
Nano SIM卡配合手机订阅起价1€/月
总计150€ + 1€/月
组装的树莓派零与4G扩展板

注意: 这个4G扩展板有很多更便宜的替代方案,电池也一样。

软件

组件费用
Cloudflare上的域名设置~
Cloudflare隧道免费

步骤

硬件组装

  • 关闭树莓派
  • 将扩展板插到树莓派零的顶部,应该看起来像这样:
4G扩展板安装在树莓派零上
  • 在4G扩展板中插入一张nano SIM卡

软件设置

安装操作系统

下载树莓派镜像工具:https://www.raspberrypi.com/software/

将树莓派操作系统精简版(零W用32位,零2 W用64位)烧录到你的MicroSD卡。

在镜像工具的高级选项(齿轮图标)中,在写入之前:

  • 设置主机名(例如solar)——这是你SSH登录的方式:ssh <user>@solar
  • 设置你的用户名和密码(例如thylong)
  • 启用SSH并使用你的公钥
  • 添加你的WiFi凭据——树莓派在首次启动时需要互联网访问才能激活树莓派连接

注意: 如果你没有键盘或显示器连接到树莓派,请确保提供有效的WiFi凭据并开启树莓派连接,这样你就可以使用屏幕共享。

树莓派连接到服务可能需要几分钟。如果5分钟后设备仍未出现,可能是WiFi和/或互联网连接不成功。你需要重新进行SD卡烧录阶段。

常见错误:错误的WiFi SSID、密码拼写错误或无效的认证密钥。

配置4G/LTE扩展板

启动树莓派。

确保扩展板正确连接

确保扩展板上的LED:

  • PWR灯亮着
  • NET灯闪烁模式:
    • 慢闪(1秒亮/1秒灭)= 正在搜索网络
    • 快闪(100ms)= 已注册并连接 ✓

如果30秒后NET灯仍然关闭或慢闪,说明扩展板与树莓派零的物理连接不正确,或者SIM卡未被识别。

SIM7600 4G扩展板顶部和底部

确保从树莓派连接扩展板

连接到树莓派连接

安装所需软件包:

sudo apt update && sudo apt install -y minicom modemmanager network-manager

打开终端,确保/boot/firmware/config.txt中存在以下两行:

enable_uart=1
dtoverlay=disable-bt

这两行释放了GPIO头上的UART引脚,调制解调器使用这些引脚进行串行通信。没有它们,扩展板可能无法正确检测。

如果你做了任何修改,重新启动以应用(sudo reboot)。

然后运行ls /dev/ttyU*来列出ttys,树莓派应该已经通过USB检测到扩展板并输出:

/dev/ttyUSB0 /dev/ttyUSB1 /dev/ttyUSB2 /dev/ttyUSB3 /dev/ttyUSB4

以下是ttys的简单映射:

端口功能
/dev/ttyUSB0诊断
/dev/ttyUSB1GPS/NMEA
/dev/ttyUSB2AT命令 ← 使用这个
/dev/ttyUSB3PPP/数据
/dev/ttyUSB4音频/其他

你可以通过AT命令端口测试通信:

sudo minicom -D /dev/ttyUSB2 -b 115200

然后:

  1. 按Ctrl+A然后按E启用回显
    1. 输入AT+回车
    2. → 应返回OK
  2. 然后验证SIM卡:
    1. 输入AT+CPIN?
    2. → 应返回+CPIN: READY
  3. 然后验证网络
    1. 输入AT+COPS?
    2. → 应显示Orange详情(如果你使用Orange多SIM卡)

其他测试用AT命令(供好奇者参考):

AT命令描述返回值
ATAT测试命令OK
ATEATE1:开启回显,ATE0:关闭回显OK
AT+CGMI请求制造商识别OK
AT+CGMM请求型号识别OK
AT+CGSN请求产品序列号识别OK
AT+CSUB请求产品版本OK
AT+CGMR请求固件版本OK
AT+IPREX配置模型波特率+IPREX:OK
AT+CRESET重置模型OK
AT+CSQ查询信号质量OK
AT+CPIN?查询SIM卡状态+CPIN:READY
AT+COPS?查询运营商信息+COPS:OK
AT+CREG?查询网络注册状态+CREG: OK
AT+CPSI?查询UE系统信息
AT+CNMP选择网络模式OK

如果你到了这一步,恭喜——调制解调器准备好创建连接了!

如果你使用minicom时遇到任何错误或没有预期输出,请检查mmcli -L的输出,它会帮助调试。

要创建连接,运行以下命令:

我们使用APNorange(不是orange.fr)。orange.fr APN用于网络共享并禁用IPv6——我们需要orange来稍后获取公共IPv6地址。

sudo nmcli connection add type gsm ifname '*' con-name orange-4g apn orange
sudo nmcli connection up orange-4g
sudo nmcli connection modify orange-4g connection.autoconnect yes

要测试连接,使用curl:

curl --interface wwan0 https://ifconfig.me

如果你看到你的公共IP,恭喜,你已经连接到4G了!

启用IPv6并使其持久化

Orange的4G在IPv4(CGNAT)和IPv6(防火墙)上都阻止入站连接。但是,Cloudflare隧道需要在端口7844上进行出站连接——Orange在IPv4上阻止了这个端口,但在IPv6上允许。因此,我们需要配置双栈IPv4v6并使其在重启后持久化。

# 将初始EPS承载设置为双栈
sudo mmcli -m 0 --3gpp-set-initial-eps-bearer-settings="apn=orange,ip-type=ipv4v6"

# 用双栈重新连接
sudo mmcli -m 0 --simple-disconnect && sleep 3 && sudo mmcli -m 0 --simple-connect="apn=orange,ip-type=ipv4v6"

# 从承载读取IPv6配置并应用到wwan0
BEARER=$(mmcli -m 0 --output-json | grep -o "/org/freedesktop/ModemManager1/Bearer/[0-9]*" | tail -1)
IPV6=$(mmcli -b ${BEARER##*/} --output-json | grep -oP '"address"\s*:\s*"\K[0-9a-f:]+(?=")' | head -1)
GW=$(mmcli -b ${BEARER##*/} --output-json | grep -oP '"gateway"\s*:\s*"\K[0-9a-f:]+(?=")' | head -1)
sudo ip -6 addr add ${IPV6}/64 dev wwan0
sudo ip -6 route add default via ${GW} dev wwan0

# 验证——应返回你的公共IPv6
curl -6 -s --interface wwan0 https://ifconfig.me && echo

上面分配的IPv6地址在重启后会丢失。为了使其持久化,创建一个systemd oneshot服务,在每次调制解调器连接后重新应用它:

sudo tee /usr/local/bin/apply-ipv6.sh << 'EOF'
#!/bin/bash
sleep 5
BEARER=$(mmcli -m 0 --output-json | grep -o "/org/freedesktop/ModemManager1/Bearer/[0-9]*" | tail -1)
IPV6=$(mmcli -b ${BEARER##*/} --output-json 2>/dev/null | grep -oP '"address"\s*:\s*"\K[0-9a-f:]+(?=")' | head -1)
GW=$(mmcli -b ${BEARER##*/} --output-json 2>/dev/null | grep -oP '"gateway"\s*:\s*"\K[0-9a-f:]+(?=")' | head -1)
if [ -n "$IPV6" ] && [ -n "$GW" ]; then
    ip -6 addr add ${IPV6}/64 dev wwan0 2>/dev/null || true
    ip -6 route add default via ${GW} dev wwan0 2>/dev/null || true
fi
EOF
sudo chmod +x /usr/local/bin/apply-ipv6.sh
sudo tee /etc/systemd/system/wwan-ipv6.service << 'EOF'
[Unit]
Description=Apply IPv6 to wwan0
After=ModemManager.service network-online.target
Wants=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/apply-ipv6.sh
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload && sudo systemctl enable --now wwan-ipv6

验证IPv6在重启后仍然有效:

sudo reboot
# 重新连接后:
ip -6 addr show wwan0
# 预期:一个全局IPv6地址(以2a01:或类似开头)

设置Web服务器

由于CGNAT和移动运营商防火墙通常会阻止其4G网络上的入站请求,我们需要使用反向隧道。有多种解决方案可用:Cloudflare隧道、使用VPS进行流量转发等。

我们将使用Cloudflare隧道,因为它简单、免费,并且不需要额外资源。在本教程中,我们假设你已经在Cloudflare上获取并设置了自己的域名(参见上面的前提条件)。

使用darkhttpd将Hugo博客部署到树莓派

在本地构建Hugo站点

安装Hugo并使用主题搭建新站点:

# 安装Hugo(macOS)
brew install hugo

# 创建新站点
hugo new site myblog && cd myblog

# 添加主题(例如Ananke)
git init
git submodule add https://github.com/theNewDynamic/gohugo-theme-ananke.git themes/ananke
echo "theme = 'ananke'" >> hugo.toml

# 创建你的第一篇文章
hugo new content posts/hello-world.md
# 编辑content/posts/hello-world.md,设置draft: false

# 本地预览
hugo server

准备部署时,构建生产站点:

hugo --environment production --minify

这会在public/中生成静态站点(所有HTML、CSS、JS和准备提供的资源)。

同步到树莓派

将<user>和<hostname>替换为你在镜像工具中设置的值。

ssh <user>@<hostname> 'sudo mkdir -p /var/www/myblog && sudo chown <user>:<user> /var/www/myblog'
rsync -avz --delete public/ <user>@<hostname>:/var/www/myblog/
安装darkhttpd
ssh -t <user>@<hostname> 'sudo apt-get update -qq && sudo apt-get install -y -qq darkhttpd'
创建systemd服务

隧道将配置为指向http://localhost:8080,所以darkhttpd必须监听8080端口。

sudo tee /etc/systemd/system/myblog.service << 'EOF'
[Unit]
Description=My blog (darkhttpd)
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/bin/darkhttpd /var/www/myblog --port 8080
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF
启用并启动
sudo systemctl daemon-reload
sudo systemctl enable --now myblog
sudo systemctl status myblog

预期输出:Active: active (running)

本地验证
curl -s http://localhost:8080/ | head -5

预期输出:博客HTML的前几行。博客现在在8080端口上提供服务,准备好让Cloudflare隧道转发流量到它。

设置Cloudflare隧道

注意:Orange在IPv4上阻止端口7844 cloudflared通过端口7844(QUIC)连接到Cloudflare的边缘。Orange在IPv4上阻止了此端口,但在IPv6上允许。我们用--edge-ip-version 6强制cloudflared使用IPv6——这就是为什么上面的IPv6持久化设置需要在此步骤之前完成。

在Cloudflare中创建隧道
  1. 前往Cloudflare Zero Trust https://one.dash.cloudflare.com → Networks → Tunnels
  2. 创建一个隧道(例如solar)
  3. 添加公共主机名:solar.<your_domain>.com → http://localhost:8080
  4. 复制隧道令牌
在树莓派上安装cloudflared
curl -fSL -o /tmp/cloudflared https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm
sudo mv /tmp/cloudflared /usr/local/bin/cloudflared
sudo chmod +x /usr/local/bin/cloudflared
存储隧道令牌
sudo mkdir -p /etc/cloudflared
echo 'TUNNEL_TOKEN=<your-token>' | sudo tee /etc/cloudflared/env
sudo chmod 600 /etc/cloudflared/env
创建systemd服务
sudo tee /etc/systemd/system/cloudflared.service << 'EOF'
[Unit]
Description=Cloudflare Tunnel
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/local/bin/cloudflared tunnel --no-autoupdate --edge-ip-version 6 run --token ${TUNNEL_TOKEN}
EnvironmentFile=/etc/cloudflared/env
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

关键标志是--edge-ip-version 6:这强制cloudflared通过IPv6连接到Cloudflare,绕过Orange在IPv4上的端口7844阻止。

启用并启动
sudo systemctl daemon-reload
sudo systemctl enable --now cloudflared
sudo systemctl status cloudflared

预期输出:Active: active (running)

验证
journalctl -u cloudflared --no-pager -n 10

寻找包含Connection established或Registered tunnel connection的行——这确认隧道已启动。你还会在Cloudflare Zero Trust仪表板中看到隧道标记为Healthy。

Cloudflare隧道显示健康状态

然后从任何设备:curl https://solar.<your_domain>.com/

下一步——第2部分:完全离网

博客已经上线,通过4G提供服务,通过Cloudflare隧道传输。但它仍然插在墙上。

在第2部分中,我们将完全切断电源线:

  • 太阳能板——连接10W USB-C面板为树莓派在白天供电
  • 电池扩展板(Pi Sugar 3 Plus)——储存能量以度过夜晚和阴天
  • GPS——使用SIM7600扩展板上的内置GPS模块为设备进行地理标记
  • 省电技巧——禁用未使用的硬件(HDMI、LED、USB)以节省每一毫瓦

其他

有用链接