外观
Nginx 部署
适合谁
服务器上已经有 Nginx(或者你习惯用 Nginx)的人。整体结构:
text
浏览器 ──HTTPS──► Nginx ──┬── /、/admin/ ─────► 静态网页(/opt/zebra/web)
└── /api/ 等 ───────► zebra-store(127.0.0.1:8081,systemd 守护)准备
| 项目 | 要求 |
|---|---|
| 服务器 | 64 位 Linux,下面以 Debian 12 / Ubuntu 22.04+ 为例,全程用 root |
| 域名 | shop.example.com 的 A 记录指向服务器,80/443 已放行 |
| 文件 | zebra-store、storefront/dist、admin/dist、config.example.yml |
获取程序和网页
一共需要三样东西:
| 东西 | 是什么 | 怎么得到 |
|---|---|---|
zebra-store | 后端程序(一个文件) | 在 backend/ 编译 |
storefront/dist | 用户前台网页 | 在 storefront/ 打包 |
admin/dist | 管理后台网页 | 在 admin/ 打包,必须带 --base=/admin/ |
在你自己的电脑(装好 Rust ≥ 1.90 和 Node.js ≥ 20)上执行:
bash
git clone <仓库地址> zebra-store && cd zebra-store
# 1) 后端:给 Linux 服务器编译一个不依赖任何系统库的静态程序
cargo install cargo-zigbuild # 第一次需要;macOS 还要 brew install zig
cd backend
rustup target add x86_64-unknown-linux-musl
cargo zigbuild --release -p zs-server --target x86_64-unknown-linux-musl
# 产物:backend/target/x86_64-unknown-linux-musl/release/zebra-store
cd ..
# 2) 用户前台
cd storefront && npm ci && npm run build && cd .. # 产物:storefront/dist
# 3) 管理后台(放在 /admin/ 路径下)
cd admin && npm ci && npx vite build --base=/admin/ && cd .. # 产物:admin/dist直接在 Linux 服务器上编译
如果你就在 x86_64 Linux 服务器上编译,后端可以简单地用 cargo build --release -p zs-server,产物在 backend/target/release/zebra-store。 服务器是 ARM(arm64)的话,把上面的 x86_64-unknown-linux-musl 换成 aarch64-unknown-linux-musl。
为什么后台要加 --base=/admin/
后台网页默认假设自己放在网站根目录。我们把它放在 https://你的域名/admin/, 所以打包时要告诉它“我的根路径是 /admin/”,否则打开后台时 JS 文件会 404,页面一片空白。
步骤
1. 安装 Nginx 和 certbot
bash
apt update
apt install -y nginx certbot python3-certbot-nginx sqlite32. 上传文件到固定目录
在服务器上创建目录:
bash
mkdir -p /opt/zebra/{data,uploads,web}在你的电脑上上传:
bash
scp backend/target/x86_64-unknown-linux-musl/release/zebra-store root@服务器:/opt/zebra/
scp -r storefront/dist root@服务器:/opt/zebra/web/storefront
scp -r admin/dist root@服务器:/opt/zebra/web/admin
scp backend/config.example.yml root@服务器:/opt/zebra/config.yml最终目录:
text
/opt/zebra/
├── zebra-store # 后端程序
├── config.yml # 配置
├── data/ # SQLite 数据库(自动创建 zebra.db)
├── uploads/ # 上传的图片
└── web/
├── storefront/ # 里面直接是 index.html 和 assets/
└── admin/写配置文件
从仓库复制 backend/config.example.yml,改名为 config.yml,至少改下面这些 (每一项的含义见 配置文件详解):
yaml
app:
secret_key: 第一串随机字符 # openssl rand -hex 24 生成
server:
host: 127.0.0.1 # 只让本机的反向代理访问后端
port: 8081
mode: release
jwt:
secret: 第二串随机字符
user_jwt:
secret: 第三串随机字符
bootstrap:
default_admin_username: admin
default_admin_password: 你的管理员密码 # 只在第一次启动时用来创建超级管理员
database:
url: sqlite://data/zebra.db?mode=rwc # 相对“运行目录”,即 <程序目录>/data/zebra.db
upload:
dir: uploads # 相对“运行目录”
cors:
allowed_origins: ["https://shop.example.com"]三个密钥
app.secret_key、jwt.secret、user_jwt.secret 必须是三个不同的值,每个至少 16 个字符, 不能保留示例里的 change-me-…,否则程序拒绝启动并在日志里写明是哪一项。 app.secret_key 用来加密数据库里的敏感字段(支付密钥等),上线后不要再改,改了之前加密的数据就解不开了。
3. 创建运行用户
bash
useradd --system --home /opt/zebra --shell /usr/sbin/nologin zebra
chown -R zebra:zebra /opt/zebra
chmod 600 /opt/zebra/config.yml
chmod +x /opt/zebra/zebra-store
chmod o+rx /opt/zebra /opt/zebra/web # 让 Nginx(www-data)能读取网页文件4. 用 systemd 运行后端
创建 /etc/systemd/system/zebra-store.service:
ini
[Unit]
Description=Zebra Store
After=network-online.target
Wants=network-online.target
[Service]
User=zebra
Group=zebra
WorkingDirectory=/opt/zebra
ExecStart=/opt/zebra/zebra-store --config /opt/zebra/config.yml serve
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
ProtectSystem=full
ReadWritePaths=/opt/zebra
[Install]
WantedBy=multi-user.targetbash
systemctl daemon-reload
systemctl enable --now zebra-store
systemctl status zebra-store --no-pager # 应显示 active (running)
curl -s http://127.0.0.1:8081/api/v1/public/config | head -c 1205. 写 Nginx 站点配置
哪些路径要转给后端
前台和后台只是静态网页,所有数据都来自后端。反向代理必须把下面这些路径转发给后端 127.0.0.1:8081, 并保留原始的 Host 头:
| 路径 | 用途 |
|---|---|
/api/ | 所有接口,包括支付回调和对接接口 |
/uploads/ | 上传的图片 |
/sitemap.xml、/robots.txt | 搜索引擎 |
/shared/ | 异次元发卡把本站当上游时调用(异次元对接) |
/plugin/open-api/ | 萌次元协议把本站当上游时调用(萌次元对接) |
其余路径:/admin/ 开头的返回后台网页,其他的返回前台网页;找不到文件时返回对应的 index.html (前台和后台都是单页应用,刷新 /products/xxx 这类地址时服务器上并没有这个文件)。
一定要保留 Host 头
后端靠 Host 判断访问的是主站还是哪个分站,生成支付回调地址时也会用到。
创建 /etc/nginx/sites-available/zebra.conf(CentOS / 宝塔以外的 RHEL 系放在 /etc/nginx/conf.d/zebra.conf):
nginx
server {
listen 80;
listen [::]:80;
server_name shop.example.com;
client_max_body_size 20m;
# 接口、图片、SEO 文件、兼容对接协议 → 后端
location ~ ^/(api|uploads|shared|plugin/open-api)/ {
proxy_pass http://127.0.0.1:8081;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 120s;
}
location = /sitemap.xml { proxy_pass http://127.0.0.1:8081; proxy_set_header Host $host; }
location = /robots.txt { proxy_pass http://127.0.0.1:8081; proxy_set_header Host $host; }
# 管理后台
location = /admin { return 308 /admin/; }
location /admin/ {
alias /opt/zebra/web/admin/;
try_files $uri $uri/ /admin/index.html;
}
# 用户前台
location / {
root /opt/zebra/web/storefront;
try_files $uri $uri/ /index.html;
}
# 打包文件名带哈希,可以长期缓存
location /assets/ {
root /opt/zebra/web/storefront;
expires 1y;
add_header Cache-Control "public, immutable";
}
}启用并检查:
bash
ln -s /etc/nginx/sites-available/zebra.conf /etc/nginx/sites-enabled/zebra.conf
rm -f /etc/nginx/sites-enabled/default # 如果这台机器上没有别的网站
nginx -t && systemctl reload nginx此时 http://shop.example.com 应该已经能打开。
6. 申请 HTTPS 证书
bash
certbot --nginx -d shop.example.com --redirect -m 你的邮箱 --agree-toscertbot 会自动在上面的配置里加上 listen 443 ssl 和证书路径,并把 HTTP 跳转到 HTTPS。 证书会通过 systemd 定时任务自动续期,可以用 certbot renew --dry-run 检查。
让后端拿到买家的真实 IP
风控、限流和登录日志都需要买家的真实 IP。反向代理通过 X-Forwarded-For 头把 IP 传给后端, 但后端只相信 server.trusted_proxies 里列出的代理。默认值是 127.0.0.1/32 和 ::1/128, 反向代理和后端在同一台机器上时不用改。
反向代理在别的机器或者 Docker 容器里时,把它的 IP 或网段加进去,例如:
yaml
server:
trusted_proxies: ["127.0.0.1/32", "::1/128", "172.28.0.0/24"]0.0.0.0/0 这种“相信所有人”的写法会被拒绝,因为那样任何人都能伪造 IP。
验证
逐项检查:
- [ ]
https://你的域名/能打开前台,标题是你的站点名; - [ ]
https://你的域名/admin/能打开后台登录页,用admin和配置里的密码能登录; - [ ]
https://你的域名/api/v1/public/config返回一段 JSON(开头是{"status_code":0); - [ ] 在
https://你的域名/products页面按 F5 刷新,不会出现 404; - [ ] 后台 内容管理 → 素材管理 上传一张图片,能正常显示(说明
/uploads/转发正常); - [ ] 浏览器地址栏有小锁,证书有效。
登录后台后,按 部署完成后要做的事 继续。
升级
bash
# 1. 备份(见下方)
# 2. 上传新文件到临时位置,然后:
systemctl stop zebra-store
install -m 755 -o zebra -g zebra /tmp/zebra-store /opt/zebra/zebra-store
rm -rf /opt/zebra/web/storefront /opt/zebra/web/admin
mv /tmp/storefront-dist /opt/zebra/web/storefront
mv /tmp/admin-dist /opt/zebra/web/admin
systemctl start zebra-store新版本启动时会自动补齐新表和新字段,业务数据保留。
备份
要备份的只有三样:数据库、上传目录 uploads/、配置文件 config.yml(里面有加密密钥)。
bash
# SQLite 在线备份(不用停服务;需要 sqlite3:apt install sqlite3)
sqlite3 数据目录/zebra.db ".backup '/root/backup/zebra-$(date +%F).db'"
tar czf /root/backup/uploads-$(date +%F).tgz -C 程序目录 uploads
cp 程序目录/config.yml /root/backup/config-$(date +%F).ymlMySQL / PostgreSQL、定时备份和恢复步骤见 备份与升级。
这一页的“数据目录”是 /opt/zebra/data,“程序目录”是 /opt/zebra。
常见问题
502 Bad Gateway 后端没运行。systemctl status zebra-store 和 journalctl -u zebra-store -n 50 查看原因,最常见的是三个密钥不合格。
403 Forbidden 或者打开网页 404 Nginx 读不到网页文件:确认 /opt/zebra/web/storefront/index.html 存在,并且执行过 chmod o+rx /opt/zebra /opt/zebra/web。
后台 /admin/ 空白、控制台 JS 404 后台打包时没加 --base=/admin/。重新打包上传。
风控 / 登录日志里全是 127.0.0.1proxy_set_header X-Forwarded-For 没配,或者 Nginx 不在本机、没加进 trusted_proxies。
client intended to send too large body 上传的图片超过 client_max_body_size,调大它(后端自身上限由 upload.max_size 决定,默认 10 MB)。