Skip to content

服务器 + 内网穿透部署(Orange Pi) ​

将 Vistack 后端全套部署在 Orange Pi(ARM64 单板) 上,通过公网服务器 + frp 隧道映射对外;前端继续托管在 Cloudflare Pages。适合「前端上 CDN、后端在低成本 ARM 设备」的场景。

宿主机已有 Traefik / Dokploy?

若 Orange Pi 上已有其他反向代理占用 80/443(如 Dokploy 自带的 dokploy-traefik),有两种处理方式:

  1. 改端口保留自有 Traefik(推荐):Vistack 的 Traefik 继续负责内部路径分流(auth / api / 媒体 / 页面),只把宿主端口从 80 改到其他端口(如 TRAEFIK_HTTP_PORT=8082);
  2. 跳过自有 Traefik:使用 compose.server.yml override 不起 traefik,由公网服务器 Caddy 按路径分流(见文末「备选」)。

适用架构(推荐:保留 Traefik + 改端口) ​

Cloudflare Pages(cvistack.pages.dev,前端)
        │ VITE_API_BASE=https://api.你的域名/api/v1
        ▼
公网服务器(VPS:域名解析 + HTTPS 终止 + 隧道入口)
  ├─ Caddy ── 自动申请 Let's Encrypt 证书,统一转发(无需分路径)
  └─ frps(隧道服务端,端口 7000;本地 18080 供 Caddy 反代)
        ▲  frp 隧道(Orange Pi 主动连出,仅映射 1 个端口)
        ▼
Orange Pi(ARM64,内网)—— Docker Compose 全套后端
  └─ Traefik(宿主端口 8082)统一分流:
     ├─ /api/v1/auth|user → auth:8081
     ├─ /api/v1/*         → api:8080
     ├─ /vistack/*(媒体)  → minio:9000
     └─ 其余(页面)        → api:8080(内置 web 产物)

前置条件 ​

项要求
域名自己的域名,解析 api.你的域名 → 公网服务器 IP
公网服务器VPS,开放 80 / 443 / 7000(frp 控制端口)
Orange PiARM64(uname -m 应为 aarch64),建议 ≥ 8GB 内存
端口确认8082 / 8083 / 9000 / 5432 / 6379 / 9092 / 2379 未被占用(ss -tlnp 检查)

镜像 ARM64 兼容性 ​

镜像ARM64说明
golang / node / alpine / postgres / redis / traefik / minio✅官方 multi-arch,Docker 自动拉取 arm64
quay.io/coreos/etcd:v3.5.16✅官方提供 arm64
confluentinc/cp-kafka:7.6.1⚠️Confluent 7.4+ 提供 arm64,需实测;不兼容则改 compose 镜像为 apache/kafka

第 1 步:Orange Pi 准备 ​

bash
uname -m                            # 应为 aarch64
curl -fsSL https://get.docker.com | sh
sudo systemctl enable --now docker

第 2 步:Orange Pi 部署 Vistack ​

bash
git clone https://github.com/binhy/vistack.git && cd vistack

# 环境变量:改所有默认密码、MinIO 密钥、JWT_SECRET,并给 Traefik 换端口
cp .env.example .env.local
vim .env.local

.env.local 追加(避开 Dokploy 占用的 80/443):

bash
TRAEFIK_HTTP_PORT=8082          # 统一入口(Vistack Traefik 宿主端口)
TRAEFIK_DASHBOARD_PORT=8083     # Traefik 仪表盘

修改 conf/app.docker.toml(两处必改):

toml
[cors]
allow_origins = ["https://cvistack.pages.dev"]   # ① 前端 Pages 域名

[minio]
public_endpoint = "https://api.你的域名"          # ② 统一 HTTPS 入口(经 Caddy → frp → Traefik 媒体路由)

起栈(含 traefik,端口为 8082/8083):

bash
docker compose up -d --build

验证本机入口:

bash
curl http://localhost:8082/health      # {"db":"ok","minio":"ok",...}

Auth 服务私钥生产环境必须固定:启动时注入 VISTACK_AUTH_RSA_PRIVATE_KEY_FILE(PEM 文件),否则重启后已签发 token 全部失效。

第 3 步:frp 隧道(只需映射 1 个端口) ​

公网服务器 —— frps(/etc/frp/frps.toml):

toml
bindPort = 7000
auth.method = "token"
auth.token = "换成强随机token"
bash
sudo frps -c /etc/frp/frps.toml

Orange Pi —— frpc(/etc/frp/frpc.toml):

toml
serverAddr = "公网服务器IP"
serverPort = 7000
auth.method = "token"
auth.token = "换成强随机token"

[[proxies]]
name = "vistack"
type = "tcp"
localIP = "127.0.0.1"
localPort = 8082                      # Vistack Traefik(内部已按路径分流)
remotePort = 18080

⚠️ frp 的 remotePort:18080 监听在公网服务器所有接口,请用防火墙仅放行本机访问(如 ufw allow from 127.0.0.1 to any port 18080),避免绕过 Caddy 直连。

第 4 步:公网服务器 Caddy(自动 HTTPS + 统一转发) ​

caddy
api.你的域名 {
    reverse_proxy 127.0.0.1:18080   # frp → Orange Pi Traefik,路径分流在 Traefik 完成
}
  • 域名解析:api.你的域名 A 记录 → 公网服务器 IP;
  • Caddy 首次启动自动申请 Let's Encrypt 证书并续期;
  • 媒体 /vistack/* 也走同一入口:Caddy → frp → Traefik media-router → MinIO,签名 Host 全程为 api.你的域名,与 public_endpoint 一致。

第 5 步:前端联动 ​

Cloudflare Pages 项目 → Settings → Environment variables(Production):

VITE_API_BASE = https://api.你的域名/api/v1

保存后重新部署(环境变量仅构建时生效)。验证:

bash
curl https://api.你的域名/health
curl https://api.你的域名/vistack/xxxx   # 应返回 MinIO 响应(403/200),而非页面

备选:跳过自有 Traefik + Caddy 分路径 ​

不想在 Orange Pi 上跑 Vistack 的 Traefik 时(零额外容器),使用 compose.server.yml override 起栈:

bash
docker compose -f compose.yml -f compose.server.yml up -d --build
# traefik 被隔离到 local-only profile,不启动;api(8080)/auth(8081)/minio(9000) 直连

frpc 映射 3 个端口:

toml
[[proxies]]   # vistack-api    localPort = 8080  remotePort = 18080
[[proxies]]   # vistack-auth   localPort = 8081  remotePort = 18081
[[proxies]]   # vistack-minio  localPort = 9000  remotePort = 19000

Caddy 按路径分流(auth 规则必须在 /api/* 之前):

caddy
api.你的域名 {
    handle /api/v1/auth/*  { reverse_proxy 127.0.0.1:18081 }
    handle /api/v1/user/*  { reverse_proxy 127.0.0.1:18081 }
    handle /api/*          { reverse_proxy 127.0.0.1:18080 }
    handle /vistack/*      { reverse_proxy 127.0.0.1:19000 }
    handle                 { reverse_proxy 127.0.0.1:18080 }
}

性能调优(Orange Pi) ​

  • 转码:FFmpeg 无 GPU 加速,DASH 多档位转码较慢。建议接受低档位输出,或仅按需触发(transcoder 副本保持 1);
  • 内存:全套 + Kafka(KRaft)建议 ≥ 8GB;内存吃紧可给 Kafka 容器加 KAFKA_HEAP_OPTS=-Xmx512m;
  • 并发:[kafka].concurrency 保持默认 4 即可,单板瓶颈在 CPU 不在消费者数;
  • 清理:定期 docker system prune -f 清理旧镜像与日志。

备选隧道:Tailscale 替代 frp ​

两台机器都装 Tailscale(组网后互访内网 IP),公网服务器 Caddy 直接反代 Orange Pi 的 Tailscale IP:

caddy
api.你的域名 {
    reverse_proxy http://100.x.x.x:8082   # Orange Pi 的 Tailscale IP + Traefik 端口
}

免 frp 端口配置、隧道加密、断线自动重连,个人场景更省心。

安全清单 ​

  • [ ] .env.local 替换全部默认密码 / JWT_SECRET;
  • [ ] Auth RSA 私钥固定注入(VISTACK_AUTH_RSA_PRIVATE_KEY_FILE);
  • [ ] frp 设置强随机 auth.token;
  • [ ] 公网服务器防火墙仅放行 80 / 443 / 7000(18080 等仅本机);
  • [ ] 宿主机 Dokploy 等既有服务保持原样,不相互影响;
  • [ ] Traefik 仪表盘(8083)仅内网访问或关闭;
  • [ ] Orange Pi 关闭不必要的系统服务,保持 Docker 网络隔离。

故障排查 ​

现象排查
https://api.你的域名 502/522frpc 是否连接成功(frpc 日志)→ curl localhost:8082/health(Orange Pi 本机)→ Caddy 日志 → 防火墙是否放行 frp 端口
页面能开但接口报错VITE_API_BASE 是否已配且重新部署;CORS 是否含 Pages 域名
80 端口仍冲突确认 .env.local 的 TRAEFIK_HTTP_PORT 已生效(docker compose config 查看 published 端口)
视频播放失败是否 mixed content(页面 HTTPS 加载 HTTP 资源);public_endpoint 是否为 https://api.你的域名;curl https://api.你的域名/vistack/xxx 应返回 MinIO 响应
登录后 token 失效Auth 私钥未固定(重启后临时密钥变更)——生产必须注入固定私钥
起栈时报端口占用宿主机已有服务占用 8082/9000 等——先 ss -tlnp 排查,再通过 .env.local 的 *_PORT 调整

基于 MIT License 发布