想在外面用手机看 NAS 上的书,或者把简单书房装到手机桌面,都需要从外网用 HTTPS 访问。本文介绍速度最快的一种做法:手机直接连到家里的 NAS,不经过任何中转。

整体分四块:

  1. DDNS:让域名始终指向家里当前的公网 IP。绿联 NAS 自带,支持 Cloudflare。
  2. 证书:用 acme.sh 容器申请 Let's Encrypt 免费证书,到期前自动续签,直接写进简单书房的证书文件夹。
  3. 开启 HTTPS:在简单书房的设置里打开开关(1.3.0 起支持)。
  4. 端口转发:在路由器上把一个端口转到 NAS。

简单书房只负责「用你的证书提供 HTTPS」,不会帮你申请或续签证书。证书由下面的 acme.sh 负责。

全文以域名 book.example.com、外网端口 18443、NAS 路径 /volume1/docker/... 为例,换成你自己的即可。

先确认能不能直连

1. 家里有没有公网 IP

  • 在路由器管理页看「WAN 口 IP」,再用手机连家里 Wi-Fi 打开 ip.cn 看显示的 IP。两个一致才是公网 IPv4。
  • 不一致说明在运营商的大内网里,可以打电话找运营商要公网 IP(多数地区免费);或者使用 IPv6(手机流量基本都支持,需要路由器开启 IPv6 并放行 NAS)。

2. 端口:国内家庭宽带一般封了 80 和 443,要用别的端口,本文用 18443。

3. 域名:需要一个托管在 Cloudflare 上的域名(几块钱一年的就够)。只有 IP、没有域名时拿不到浏览器信任的证书,也就没法装到手机桌面。

拿不到公网 IP 的话,直连这条路走不通,可以改用 Tailscale 或 Cloudflare 隧道(速度较慢),见文末。

第一步:在 Cloudflare 准备三样东西

  1. API Token:右上角头像 → My Profile → API Tokens → Create Token,选模板 Edit zone DNS,Zone Resources 选 Include → Specific zone → 你的域名,创建。Token 只显示一次,是一串 40 位左右的字母数字,复制下来保存好。不要复制页面上的示例命令或链接。
  2. 账户 ID(Account ID):进入域名的概览页,右下角「API」一栏。
  3. 区域 ID(Zone ID):同一个位置,账户 ID 上面那一行。

DDNS 和申请证书用同一个 Token。三样东西都不要发给别人,也不要贴到群里或截图里。

第二步:在绿联 NAS 上设置 DDNS

打开 控制面板 → 设备连接 → 远程访问,在「方式二」里勾选 启用DDNS支持,点 新增:

添加DDNS:DDNS服务商选 cloudflare,已注册的DDNS域名填 book.example.com,下面是 AccessKey ID 和 AccessKey 密钥

字段 填什么
DDNS服务商 cloudflare
已注册的DDNS域名 book.example.com
AccessKey ID Cloudflare 的账户 ID
AccessKey 密钥 第一步的 API Token
IPv4 / IPv6 保持「自动」

点「应用」后回到列表,能看到外部 IPv4(和 IPv6)就说明更新成功:

远程访问 → 方式二:DDNS 列表里 api.cloudflare.com 一行,显示域名和当前的外部 IP

保存后再点「编辑」,AccessKey 密钥一栏显示的是一长串加密后的内容(100 多位),不是原来的 Token。后面申请证书时要用原始 Token,不要从这里复制。

关键:回到 Cloudflare 的 DNS 页面,确认 book 这条记录的代理状态是 灰色云朵(DNS only)。如果是橙色,点成灰色。橙色会让流量绕经 Cloudflare,既慢,又不支持 18443 这类端口。

第三步:用 acme.sh 申请免费证书

acme.sh 会通过 Cloudflare 验证域名、申请 Let's Encrypt 证书,并且每天检查一次,快到期时自动续签,一次配置,之后不用管。

1. 创建 acme 项目

先在文件管理里确认简单书房的数据目录下有 certs 文件夹(没有就新建一个),例如 /volume1/docker/easy-reader/certs。

然后打开 Docker → 项目 → 创建,项目名称填 acme,存放路径选 docker/acme,Compose 配置填:

services:
  acme:
    image: neilpang/acme.sh
    container_name: acme.sh
    restart: unless-stopped
    command: daemon
    environment:
      - CF_Token=你的API令牌              # 第一步的 API Token
      - CF_Zone_ID=你的区域ID             # 第一步的 Zone ID
      - CURL_HOME=/acme.sh               # 读取 data/.curlrc(网络慢时设置超时,见下文)
    volumes:
      - ./data:/acme.sh                                  # acme.sh 的数据(账号、证书)
      - /volume1/docker/easy-reader/certs:/certs         # 简单书房数据目录下的 certs

创建项目:项目名称 acme,存放路径 docker/acme,Compose 配置已填好

把第二个挂载的路径换成你自己的简单书房数据目录,点「立即部署」。

2. 在容器终端里申请证书

打开 Docker → 容器 → acme.sh → 终端,点「新增」,命令改成 /bin/sh(这个镜像里没有 bash),确定。依次执行:

# 用 Let's Encrypt(默认是 ZeroSSL,需要额外注册)
acme.sh --set-default-ca --server letsencrypt

# 申请证书;只给一个域名用就写这一个
acme.sh --issue --dns dns_cf -d book.example.com

# 安装到简单书房的证书文件夹,以后续签也会自动覆盖这两个文件
acme.sh --install-cert -d book.example.com --ecc \
  --key-file /certs/privkey.pem --fullchain-file /certs/fullchain.pem

申请成功时会看到类似这样的输出:

[...] Verifying: book.example.com
[...] Success
[...] Verification finished, beginning signing.
[...] Downloading cert.
[...] Your cert is in: /acme.sh/book.example.com_ecc/book.example.com.cer

想让多个子域名共用一张证书,可以申请通配符证书:-d '*.example.com' -d example.com,安装时 -d '*.example.com'。

第四步:在简单书房里开启 HTTPS

1. 加上 HTTPS 端口映射

在简单书房的 Compose 配置里,ports 下加一行,左边是 NAS 上的端口,右边 3443 不要改,然后重新部署项目:

    ports:
      - "8080:3000"
      - "18443:3443"

2. 打开开关

用管理员登录,进入 设置 → 系统 → HTTPS 证书,打开 启用 HTTPS。证书已在 certs 文件夹里,状态会变成「HTTPS 已开启」,并显示域名和到期时间:

设置 → 系统 → HTTPS 证书:已打开「启用 HTTPS」,显示 HTTPS 已开启、域名、颁发者和有效期

(截图里是演示用的自签证书;你那里颁发者会显示 Let's Encrypt。)

以后 acme.sh 续签覆盖了证书文件,简单书房会自动换上新证书,不用重启。局域网里仍然可以用原来的 http://NAS地址:8080 访问,不受影响。

已经有现成证书(购买的或别处申请的)的,也可以不用 acme.sh:在这个卡片里直接上传 fullchain.pem 和 privkey.pem(私钥不能带密码),或者把这两个文件放进 certs 文件夹。缺点是到期要自己换,简单书房会在到期前 14 天提醒。

第五步:路由器端口转发

在路由器的「端口转发 / 虚拟服务器」里添加一条:外部端口 18443 → NAS 的局域网 IP,内部端口 18443,协议 TCP。各家路由器界面不同,找「端口转发」「虚拟服务器」「NAT」之类的菜单。

只转发这一个端口,不要把 NAS 管理页面(9999 等)暴露到外网。用 IPv6 时不需要转发,但要在路由器的 IPv6 防火墙里放行 NAS 的 18443。

验证

手机 关掉 Wi-Fi、用流量,打开 https://book.example.com:18443:地址栏显示安全锁、能正常登录就成功了。接着可以把它装到手机桌面。

在家里用 Wi-Fi 打开这个地址可能打不开,这是很多路由器不支持「从内网访问自己的公网地址」(NAT 回环),不影响外网使用。家里继续用局域网地址即可。

常见报错

申请证书时 Invalid format for Authorization header 或 invalid domain Token 填错了:复制成了链接、示例命令,或者复制了绿联 DDNS 里加密后的密钥。回 Cloudflare 重新创建一个 Token,只复制那串 40 位左右的字母数字,前后不要有空格和引号。改完在 Docker 里重新部署 acme 项目,环境变量才会生效。Zone ID 也要确认是这个域名的(32 位)。

申请卡住好几分钟,最后报 Cannot make POST request ... error code: 28 NAS 到 Let's Encrypt 的网络时好时坏,有的请求会一直挂着,acme.sh 默认要等 5 分钟才重试。在容器终端里执行一次:

echo 'max-time = 60' > /acme.sh/.curlrc

请求超过 60 秒就放弃并自动重试(最多 20 次)。这个文件存在挂载的 data 目录里,配合 Compose 里的 CURL_HOME=/acme.sh,以后自动续签也会用到。然后重新执行申请命令。

设置页显示「证书与私钥不匹配」「证书无法用于 HTTPS」 certs 里的两个文件不是同一张证书的,重新执行一次 --install-cert。

打不开怎么办

按顺序排查:

  1. 域名解析:在电脑上 ping book.example.com,看解析出来的是不是家里的公网 IP;不是的话检查 DDNS 列表是否显示了外部 IP、Cloudflare 记录是否为灰色云朵。
  2. 端口被封:换一个端口(比如 28443),compose 映射、路由器转发和访问地址一起改。
  3. 设置页状态:「HTTPS 证书」里是否显示「HTTPS 已开启」。
  4. 证书域名:访问用的域名要和证书上的域名一致(通配符证书覆盖 xxx.example.com)。

没有公网 IP:其他办法

  • Tailscale:手机和 NAS 都装 Tailscale,组成私有网络,在外面用 Tailscale 分配的地址访问。不需要公网 IP 和端口转发,但手机上要一直开着 Tailscale。
  • Cloudflare 隧道:无需公网 IP,Cloudflare 提供 HTTPS;国内访问速度一般较慢。

其他教程