VPS 安装部署与安全指南
本综合指南涵盖了在通用 VPS(虚拟专用服务器)上部署 InsForge 用于生产环境、使用安全最佳实践加固你的实例,以及通过安全的更新和回滚流程对其进行长期维护。适用范围:本指南与云服务商无关。它适用于任何 Linux VPS——推荐使用 Ubuntu/Debian——无论提供商是 DigitalOcean、Hetzner、Linode、Vultr、OVH,还是裸机服务器。有关特定云平台的指南(AWS EC2、GCP、Azure、Render),请参阅本节中的其他指南。
📋 目录
前提条件
开始之前,请确保你已具备以下条件:- 一台运行 Ubuntu 22.04 LTS 或 Ubuntu 24.04 LTS 的 VPS(Debian 12 同样适用)
- 服务器的 root 或 sudo 权限
- 一个已注册的域名(生产环境推荐)
- 对 Linux 命令行和 SSH 有基本了解
第一部分 — 部署
1. 服务器要求
| Resource | Minimum | Recommended |
|---|---|---|
| CPU | 2 vCPU | 4 vCPU |
| RAM | 2 GB | 4 GB+ |
| Storage | 20 GB SSD | 40 GB+ SSD |
| OS | Ubuntu 22.04+ | Ubuntu 24.04 LTS |
| Network | Public IPv4 | Public IPv4 + IPv6 |
💡 提示:对于有多用户的生产环境负载,建议从 4 GB 内存起步。使用 docker stats 监控使用情况,并根据需要进行垂直扩容。
InsForge 由以下 4 个协同运行的服务组成:
| Service | Description | Internal Port |
|---|---|---|
| PostgreSQL | Primary database | 5432 |
| PostgREST | Auto-generated REST API layer | 3000 (mapped to 5430) |
| InsForge | Node.js backend + dashboard | 7130 |
| Deno | Serverless functions runtime | 7133 |
2. 初始服务器设置
2.1 连接到你的 VPS
2.2 更新系统软件包
2.3 创建部署用户(非 root)
切勿以 root 身份运行生产服务。创建一个专用用户:2.4 设置时区
2.5 启用自动安全更新
3. 安装 Docker 和 Docker Compose
3.1 安装 Docker 引擎
3.2 将部署用户添加到 Docker 组
3.3 验证 Docker 安装
⚠️ 安全提示:将用户添加到 docker 组会授予其在主机上等同于 root 的权限。对于专用的部署用户这是可以接受的,但不应对共享服务器上的通用账户这样做。
4. 使用 Docker Compose 部署 InsForge
4.1 下载生产环境的 Docker Compose 文件
4.2 启动 InsForge
4.3 验证所有服务是否正在运行
running 或 healthy 状态:
4.4 测试健康检查端点
5. 环境变量配置
编辑你的.env 文件,为生产环境配置 InsForge:
5.1 必需变量
在投入生产之前,以下变量必须从默认值修改:⚠️ 重要:JWT_SECRET和ENCRYPTION_KEY应该使用不同的值。如果未设置ENCRYPTION_KEY,InsForge 会回退使用JWT_SECRET——但之后再轮换JWT_SECRET会永久性地损坏所有已存储的密钥(API 密钥、OAuth 令牌等)。
5.2 数据库变量
5.3 端口变量
InsForge 使用的默认端口:💡 如果这些端口与你 VPS 上的其他服务冲突,可以修改它们。
5.4 部署功能所需变量
以下变量仅在你计划使用 InsForge 的部署功能(通过控制台部署项目)时才需要。如果你不需要部署功能,可以跳过本节。⚠️ 注意:这些变量(AWS_S3_BUCKET、AWS_REGION、AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY、PROJECT_ID、MAX_FILE_SIZE)来自根目录下的.env.example设置。它们不存在于deploy/docker-compose/.env.example中,并且deploy/docker-compose/docker-compose.yml也不会将它们传递给insforge容器,因此在你的.env中设置它们对该生产环境 compose 文件没有任何效果。要使用它们,请将每一个都添加到你docker-compose.yml中insforge服务的environment块内。
5.5 可选变量
6. 反向代理设置
反向代理位于 InsForge 前面,负责 TLS 终止、HTTP/2,并提供不带端口号的干净 URL。方案 A:Nginx(推荐)
6.1 安装 Nginx
6.2 创建站点配置
insforge.yourdomain.com 替换为你的实际域名:
6.3 启用该站点
方案 B:Caddy(自动 HTTPS)
Caddy 是一个更简单的替代方案,可以自动处理 TLS 证书。安装 Caddy
配置 Caddy
7. HTTPS / TLS 设置
如果你在第 6 步中选择了 Caddy,TLS 已经自动处理完毕。请直接跳转到第二部分。
7.1 安装 Certbot(用于 Nginx)
7.2 获取 SSL 证书
- 通过 HTTP 质询验证域名所有权
- 从 Let’s Encrypt 获取签名证书
- 自动更新你的 Nginx 配置以提供 HTTPS 服务
- 设置 HTTP → HTTPS 重定向
7.3 验证自动续期
Let’s Encrypt 证书每 90 天过期一次。Certbot 会安装一个用于自动续期的 systemd 定时器:7.4 为 HTTPS 更新 InsForge 环境变量
获取证书后,更新你的.env 以使用 HTTPS 网址:
第二部分 — 安全
8. 端口管理
应对外开放的端口(通过反向代理)
| Port | Protocol | Purpose |
|---|---|---|
| 22 | TCP | SSH (restrict source IP) |
| 80 | TCP | HTTP → HTTPS redirect |
| 443 | TCP | HTTPS (reverse proxy) |
应对公众关闭的端口
以下端口仅用于 Docker 内部服务间通信,绝不应暴露给公网:| Port | Service | Why Close It |
|---|---|---|
| 5432 | PostgreSQL | Direct DB access — use docker exec instead |
| 5430 | PostgREST | Internal REST layer — proxied through InsForge |
| 7130 | InsForge | API + dashboard, accessed via reverse proxy on 443, not directly |
| 7131 | (unused) | Published by compose (AUTH_PORT), but no process listens on it |
| 7133 | Deno | Internal serverless runtime |
⚠️ 关键:默认的docker-compose.yml将端口绑定到0.0.0.0(所有接口),而非127.0.0.1。这意味着 Docker 会将服务直接暴露给互联网,完全绕过 UFW(Docker 直接操作 iptables)。你必须为docker-compose.yml中每一个发布的端口添加127.0.0.1:前缀:如果没有这个前缀,互联网上的任何人都可以直接访问这些服务——包括使用默认凭据的 PostgreSQL。详情请参见第 9.2 节。
9. 防火墙设置(UFW)
UFW(Uncomplicated Firewall)是在 Ubuntu 上管理 iptables 最简单的方式。9.1 安装和配置 UFW
⚠️ 关键:务必在启用 UFW 之前先允许 SSH,否则你会把自己锁在服务器外面。
9.2 Docker 与 UFW 的注意事项
Docker 会直接操作 iptables,这可能绕过 UFW 规则。要防止这种情况: 方案 1 — 将端口绑定到 localhost(推荐): 在你的docker-compose.yml 中,为端口加上 127.0.0.1: 前缀:
⚠️ 禁用 Docker 的 iptables 管理需要手动配置网络。对于大多数场景,推荐使用方案 1。
9.3 将 SSH 限制到你的 IP(可选)
为了最大程度的安全性,将 SSH 访问限制到已知的 IP 地址:10. 以非 root 用户运行服务
InsForge 的 Docker 镜像已经遵循了非 root 的最佳实践:- 生产环境 Dockerfile 设置了
USER node(UID 1000),因此容器内的应用进程以非 root 用户运行。 - 系统级的 Docker 操作由
deploy用户(在第 2.3 步中创建)管理,该用户通过docker组获得对 Docker 套接字的访问权限。
docker-compose.yml 中为每个服务添加 security_opt,以防止权限提升:
11. SSH 加固
11.1 使用 SSH 密钥认证
11.2 禁用密码认证
在确认基于密钥的认证可以正常工作后:11.3 安装 Fail2Ban
Fail2Ban 会自动封禁出现恶意行为(例如 SSH 暴力破解)的 IP:12. Docker 安全
12.1 保持 Docker 更新
12.2 限制容器资源(可选)
防止单个容器占用全部资源:12.3 只读根文件系统(进阶)
为了进一步加固,可以将容器文件系统尽可能挂载为只读:⚠️ 这需要经过测试——某些服务需要可写目录来存放缓存或临时文件。
12.4 限制 CORS 来源
默认情况下,后端允许所有来源。它会将请求的Origin 请求头原样反射回响应中,并且对于函数代理响应,会设置 Access-Control-Allow-Origin: *。这对本地开发很方便,但对生产环境来说过于宽松。对于生产部署,请将允许的来源限制为你实际提供服务的域名(例如你的控制台和应用域名),这样其他网站就无法向你的 API 发起带凭据的跨域请求。
13. 密钥管理
应做 ✅
- 将密钥存储在
.env文件中,并设置chmod 600 ~/insforge/.env - 为
JWT_SECRET和ENCRYPTION_KEY使用不同的值 - 使用
openssl rand -base64 32生成密钥 - 将你的
.env文件备份到安全的离线位置
不应做 ❌
- 将
.env提交到版本控制系统 - 为多个变量重复使用同一个密钥
- 在生产环境中使用默认密码(
change-this-password、postgres) - 通过未加密的渠道分享密钥
第三部分 — 更新与维护
14. 更新前备份
更新前务必先备份。 这样如果出现任何问题,你都有恢复途径。14.1 备份数据库
14.2 备份环境变量和卷
14.3 记录当前版本
15. 更新 InsForge
15.1 拉取最新镜像
15.2 应用更新
Ctrl+C 停止跟随日志。
15.3 验证更新
15.4 更新 Docker Compose 文件(如有需要)
有时新版本会包含对docker-compose.yml 的更改。要获取这些更改:
16. 回滚流程
如果更新导致了问题,请按照以下步骤进行回退:16.1 停止出问题的服务
16.2 恢复之前的 Docker Compose 文件
16.3 固定到指定的镜像版本
编辑docker-compose.yml,将 latest 标签替换为之前的版本:
注意:目前deploy/docker-compose固定使用v1.5.0,而项目目前已在 2.x 系列。请固定到你更新之前所运行的版本。
16.4 恢复数据库(如有需要)
只有当此次更新包含导致问题的数据库迁移时,才需要恢复数据库:16.5 恢复环境变量文件(如有更改)
17. 自动化备份
设置一个 cron 任务以进行每日自动备份:17.1 创建备份脚本
17.2 使用 Cron 设置计划任务
17.3 异地备份(推荐)
为了灾难恢复,将备份复制到外部位置:18. 监控与健康检查
18.1 检查服务状态
18.2 查看日志
18.3 健康检查端点
从外部监控健康检查端点。一个简单的基于 cron 的检查:https://insforge.yourdomain.com/api/health。
快速参考
常用命令
安全检查清单
- 已创建部署用户(非 root)
- 已启用 SSH 密钥认证
- 已禁用 SSH 密码认证
- 已禁用 root 登录
- 已启用 UFW 防火墙(仅开放 22、80、443 端口)
- Docker 端口已绑定到
127.0.0.1 - 已安装并启用 Fail2Ban
-
JWT_SECRET已从默认值修改(32 位以上) - 已设置
ENCRYPTION_KEY(与JWT_SECRET不同) -
ROOT_ADMIN_PASSWORD已从默认值修改 -
POSTGRES_PASSWORD已从默认值修改 -
.env文件权限已设置为600 - 已通过 Certbot 或 Caddy 启用 HTTPS
- 已配置每日自动备份
- 已启用无人值守的安全更新
故障排查
启用 UFW 后无法连接
如果你被锁在服务器外,请使用你的 VPS 提供商的网页控制台(带外访问)来执行:Docker 绕过 UFW
Docker 会直接操作 iptables。请按照第 9.2 节中描述的方式,在docker-compose.yml 中将端口绑定到 127.0.0.1。
服务无法启动
SSL 证书无法续期
端口冲突
数据库连接问题
🆘 需要帮助?
- 文档:https://docs.insforge.dev
- Discord 社区:https://discord.com/invite/MPxwj5xVvW
- GitHub Issues:https://github.com/insforge/insforge/issues