Portainer 一键部署
本文带你完成 BangNiCMS 部署 8 步流程的第 2~7 步:从 SSH 登录到 6 个容器全部 healthy。
第 2 步:SSH 登录服务器
Section titled “第 2 步:SSH 登录服务器”| 系统 | 推荐 SSH 工具 |
|---|---|
| Mac / Linux | 自带 Terminal(ssh root@IP) |
| Windows | Tabby(推荐)/ MobaXterm / PowerShell(Win10+ 自带 ssh) |
ssh root@你的服务器IP输入 yes 确认指纹 → 输入 root 密码 → 看到 root@xxx:~# 即登录成功。
第 3 步:运行初始化脚本
Section titled “第 3 步:运行初始化脚本”将下面 3 条命令依次粘贴到 SSH 窗口:
# 1) 下载脚本curl -fsSL https://raw.githubusercontent.com/miaochi998/bncms-deploy/main/init-server.sh -o /tmp/init.sh
# 2) 后台运行nohup bash /tmp/init.sh </dev/null >/tmp/bncms-init.log 2>&1 &
# 3) 实时查看进度tail -f /tmp/bncms-init.log# 1) 下载脚本curl -fsSL https://raw.githubusercontent.com/miaochi998/bncms-deploy/main/init-server.sh -o /tmp/init.sh
# 2) 后台运行(自动配 Docker 镜像加速器)nohup bash /tmp/init.sh --mirror=cn </dev/null >/tmp/bncms-init.log 2>&1 &
# 3) 实时查看进度tail -f /tmp/bncms-init.log脚本会做 3 件事(约 2-5 分钟)
Section titled “脚本会做 3 件事(约 2-5 分钟)”- 升级系统软件包(停用 unattended-upgrades + apt upgrade)
- 安装 Docker(官方
get.docker.com脚本) - 配置防火墙(ufw 放行 22 / 80 / 443 / 9443)+ 创建
/opt/bangnicms/data数据目录 + 启动 Portainer CE
脚本结束后会显示
Section titled “脚本结束后会显示”==================================================== 🎉 服务器初始化完成!==================================================== Docker : Docker version 27.x.x Portainer : https://你的IP:9443 数据目录 : /opt/bangnicms/data ...记下 Portainer URL(看到 ”🎉 服务器初始化完成” 后按 Ctrl+C 退出 tail)。
第 4 步:设置 Portainer admin(5 分钟内必须完成)
Section titled “第 4 步:设置 Portainer admin(5 分钟内必须完成)”4.1 浏览器打开 Portainer
Section titled “4.1 浏览器打开 Portainer”https://你的服务器IP:94434.2 跳过证书警告
Section titled “4.2 跳过证书警告”会弹出”您的连接不是私密连接”(因为 Portainer 用自签证书)。
- Chrome / Edge:高级 → 继续访问 …(不安全)
- Safari:显示详细信息 → 访问此网站
4.3 创建 admin 账号
Section titled “4.3 创建 admin 账号”| 字段 | 填什么 |
|---|---|
| Username | admin 或自定义 |
| Password | 至少 12 位,含大写 + 小写 + 数字 + 特殊字符 (如 MySecure@2026Pass) |
| Confirm Password | 与上面一致 |
点 Create user → Get Started → 选 local(本地 Docker 环境) → 进入 Dashboard。
第 5 步:创建 BangNiCMS Stack
Section titled “第 5 步:创建 BangNiCMS Stack”5.1 (必读)了解数据持久化:bind mount vs Docker volume
Section titled “5.1 (必读)了解数据持久化:bind mount vs Docker volume”在创建 stack 之前,必须理解 BangNiCMS 的数据存在哪里、如何清理。这决定了后续重部署 / 迁移 / 备份时该怎么做。
| 类别 | Docker volume(命名卷) | bind mount(BangNiCMS 采用) |
|---|---|---|
docker-compose.yml 语法 | - pgdata:/var/lib/postgresql/data | - /opt/bangnicms/data/postgres:/var/lib/postgresql/data |
| 数据位置 | Docker 内部路径 | 宿主机 /opt/bangnicms/data/ |
| Portainer “Volumes” 页面 | ✅ 可见、可点击删除 | ❌ 不显示(必须 SSH 到宿主机 rm -rf 删除) |
| 删 stack / 删容器 | 默认保留 | 始终保留(在宿主机目录中) |
| 备份 | docker run --rm -v vol:/d alpine tar ... | tar -czf backup.tar.gz /opt/bangnicms/data |
| 迁移 | docker volume export/import | rsync -av /opt/bangnicms/data/ 新机:/opt/bangnicms/data/ |
为什么选 bind mount?
- 备份 / 迁移零门槛(一行命令即可)
- 出问题可直接
cd /opt/bangnicms/data/postgres查看 - Borg / Restic / rsync.net / 阿里云 OSS 镜像等企业级备份工具都原生支持宿主机目录
- 宿主机
du -sh/ls可见,不会“丢了谁也不知道”
唯一代价:Portainer “Volumes” 页面看不到这些目录。请记住 4 个路径:
/opt/bangnicms/data/postgres # 主数据库/opt/bangnicms/data/redis # 缓存/opt/bangnicms/data/storage # 用户上传文件/opt/bangnicms/data/caddy # Let's Encrypt 证书 + ACME 账户5.2 (必读)准备 storage 目录权限
Section titled “5.2 (必读)准备 storage 目录权限”在 SSH 中运行以下命令一次(幂等,重复跑也安全):
# 创建 4 个数据目录mkdir -p /opt/bangnicms/data/{postgres,redis,storage,caddy}
# 关键:改变 storage 目录拥有者为 UID 1001chown -R 1001:1001 /opt/bangnicms/data/storage
# 验证ls -la /opt/bangnicms/data/# 期望看到 storage 目录 owner 是 "1001 1001"(而不是 "root root")5.3 在 Portainer 创建 Stack
Section titled “5.3 在 Portainer 创建 Stack”- 左侧菜单 → Stacks → 右上角 + Add stack
- Name 字段填:
bangnicms - Build method 选 Web editor
5.4 复制 docker-compose.yml 内容
Section titled “5.4 复制 docker-compose.yml 内容”打开浏览器新标签页访问:
https://raw.githubusercontent.com/miaochi998/bncms-deploy/main/docker-compose.yml全选 → 复制全部内容(约 250 行)→ 粘贴到 Portainer 的 Web editor 输入框(替换默认注释)。
第 6 步:填 5 个环境变量并 Deploy
Section titled “第 6 步:填 5 个环境变量并 Deploy”6.1 生成 3 个密钥
Section titled “6.1 生成 3 个密钥”回到 SSH 窗口,执行下面 3 条命令各一次:
echo "BANGNICMS_POSTGRES_PASSWORD = $(openssl rand -hex 24)"echo "BANGNICMS_JWT_SECRET = $(openssl rand -hex 24)"echo "BANGNICMS_REVALIDATE_SECRET = $(openssl rand -hex 24)"输出三串 48 位随机字符串,立即复制到密码管理器或备忘录。
6.2 在 Portainer 表单填环境变量
Section titled “6.2 在 Portainer 表单填环境变量”回到 Portainer 的 Add stack 页面,滚动到 Web editor 下方的 Environment variables 区域,点 Add environment variable 5 次,逐行填:
| Name | Value |
|---|---|
DOMAIN | 你的域名(不带 https:// 不带 www,例 mysite.com) |
ADMIN_EMAIL | 你的常用邮箱(用于 Let’s Encrypt 续期通知) |
BANGNICMS_POSTGRES_PASSWORD | 第 1 个密钥 |
BANGNICMS_JWT_SECRET | 第 2 个密钥 |
BANGNICMS_REVALIDATE_SECRET | 第 3 个密钥 |
6.3 点 Deploy the stack
Section titled “6.3 点 Deploy the stack”按钮变 Deployment in progress…:
| 时间 | 阶段 |
|---|---|
| 1-3 分钟 | 拉取 6 个镜像(postgres / redis / server / web / admin / caddy,约 1.5 GB) |
| 3-5 分钟 | 启动容器 + 初始化数据库 |
| 5-8 分钟 | Caddy 向 Let’s Encrypt 申请 HTTPS 证书 |
部署成功后跳转回 Stacks 列表,bangnicms 显示 Active。
第 7 步:验证 6 个容器全部 healthy
Section titled “第 7 步:验证 6 个容器全部 healthy”左侧菜单 → Containers → 看到 6 个:
| 容器名 | 期望状态 |
|---|---|
bangnicms-postgres | healthy ✓ |
bangnicms-redis | healthy ✓ |
bangnicms-server | healthy ✓ |
bangnicms-web | running |
bangnicms-admin | running |
bangnicms-caddy | running |
验证 HTTPS 证书已签发
Section titled “验证 HTTPS 证书已签发”curl -I https://你的域名期望看到 HTTP/2 200 或 HTTP/2 308(重定向)。看到 SSL handshake failure → 等 1 分钟再试,Caddy 还在签发。
Caddy 一直不 running
Section titled “Caddy 一直不 running”最常见原因:DNS 没生效或安全组没放行 80/443。
docker logs bangnicms-caddy --tail 60- 看到
obtained certificate→ 成功 - 看到
timeout/connection refused→ 检查 DNS 与安全组
详见 DNS 与 HTTPS。
Portainer 5 分钟超时锁定
Section titled “Portainer 5 分钟超时锁定”docker rm -f portainerdocker volume rm portainer_datadocker run -d --name portainer --restart=unless-stopped \ -p 9000:9000 -p 9443:9443 \ -v /var/run/docker.sock:/var/run/docker.sock \ -v portainer_data:/data \ portainer/portainer-ce:latestdocker pull 在国内超时
Section titled “docker pull 在国内超时”ghcr.io 偶发不稳定,把 docker-compose.yml 里所有 ghcr.io/miaochi998/bangnicms-* 替换为 ghcr.nju.edu.cn/miaochi998/bangnicms-*(南大镜像代理),然后 Stacks → Update。
server 容器 restart loop 报 P1000 或 EACCES
Section titled “server 容器 restart loop 报 P1000 或 EACCES”这是重部署时最常见问题:在 Portainer 里删了 stack/容器后又重新部署,但 server 一直 restart。
docker logs bangnicms-server --tail 30- 看到
Error: P1000: Authentication failed against database server→ 老 PG 数据还在/opt/bangnicms/data/postgres,里面的老密码 ≠ 你在 Portainer 重填的新密码 - 看到
EACCES: permission denied, mkdir '/data/plugins'→ storage 目录是 docker 用 root 重建的,UID 1001 无写入权限
修复:看下面的「想完全重新部署」。
想完全重新部署(清空所有数据)
Section titled “想完全重新部署(清空所有数据)”由于 bind mount 数据在宿主机目录中而不在 Docker volume,在 Portainer 里删 stack/容器不会清除数据。必须 SSH 到宿主机手动清除。
保留 caddy 目录以重用 Let’s Encrypt 证书(避免一周同域名重申 5 次被限流):
# 1) Portainer 删 stack 与全部 bangnicms-* 容器# Stacks → bangnicms → Delete;Containers → 勾选 bangnicms-* → Remove
# 2) SSH 删除数据目录(保留 caddy)rm -rf /opt/bangnicms/data/postgres /opt/bangnicms/data/redis /opt/bangnicms/data/storage
# 3) 重建目录并修复 storage 权限mkdir -p /opt/bangnicms/data/{postgres,redis,storage}chown -R 1001:1001 /opt/bangnicms/data/storage
# 4) 在 Portainer 重新走第五、六、七步重创建 stack# 1) Portainer 删 stack 与全部 bangnicms-* 容器(同上)
# 2) SSH 删除全部数据rm -rf /opt/bangnicms/data/{postgres,redis,storage,caddy}
# 3) 重建目录并修复 storage 权限mkdir -p /opt/bangnicms/data/{postgres,redis,storage,caddy}chown -R 1001:1001 /opt/bangnicms/data/storage
# 4) 在 Portainer 重新创建 stack,为避免 Let's Encrypt 限流请使用不同域名6 个容器全部 healthy 后,走安装向导 → 完成最后 5 步配置(环境检查 / 数据库迁移 / 创建超管 / 站点信息 / 示例数据)。