JumpServer v4.10.16-ce 华为云 ECS 实战部署全记录
从零开始在华为云 ECS (Ubuntu 24.04) 上部署 JumpServer 开源堡垒机,包含完整的踩坑记录、真实服务器执行输出、配置详解。
目录
- [1. 前言](#1. 前言)
- [2. 环境准备](#2. 环境准备)
- [3. 架构设计](#3. 架构设计)
- [4. 部署实战](#4. 部署实战)
- [5. 踩坑记录](#5. 踩坑记录)
- [6. Bug 修复:ERR_INVALID_REDIRECT](#6. Bug 修复:ERR_INVALID_REDIRECT)
- [7. 验证测试](#7. 验证测试)
- [8. 总结](#8. 总结)
1. 前言
JumpServer 是广受欢迎的开源堡垒机 (Bastion Host / PAM - Privileged Access Management),用来统一管理和审计所有对服务器的访问。
为什么需要堡垒机?
┌─────────────────────────────────────────────────────────────┐
│ 没有堡垒机 │
│ │
│ 工程师 A ──直接 SSH──► 生产服务器 (无审计,无控制) │
│ 工程师 B ──直接 SSH──► 生产服务器 (账号共享,无法追溯) │
│ 外包人员 ──直接 SSH──► 生产服务器 (权限无法细粒度控制) │
└─────────────────────────────────────────────────────────────┘
⬇ 引入 JumpServer 后
┌─────────────────────────────────────────────────────────────┐
│ 有堡垒机 │
│ │
│ 所有工程师 ──► JumpServer ──► 资产服务器 │
│ │ │
│ ├── 统一认证 (Unified Auth) │
│ ├── 权限细粒度控制 (Fine-grained ACL) │
│ ├── 操作录屏审计 (Session Recording) │
│ └── 命令过滤 (Command Filter) │
└─────────────────────────────────────────────────────────────┘
JumpServer vs 同类产品对比
| 特性 | JumpServer | Teleport | Apache Guacamole |
|---|---|---|---|
| 开源协议 | GPL v3 | 商业闭源 | Apache 2.0 |
| Web Terminal | ✅ 支持 | ✅ 支持 | ✅ 支持 |
| 资产管理 | ✅ 丰富 | ✅ 中等 | ❌ 需自行开发 |
| 操作录屏 | ✅ 完整 | ✅ 完整 | ⚠️ 需插件 |
| 中文文档 | ✅ 完善 | ⚠️ 一般 | ❌ 较少 |
| 部署复杂度 | 中等 (Docker) | 简单 | 较高 |
| 社区活跃度 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ |
2. 环境准备
2.1 服务器信息
本次部署使用华为云 (Huawei Cloud) 中国香港区域 ECS 服务器:
┌─────────────────────────────────────────────────────────────┐
│ ecs-f763 集群 │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ jms2-01 │ │ jms2-02 │ │
│ │ 27.106.107.121 │ │ 119.12.172.218 │ │
│ │ 资产节点 │ │ 资产节点 │ │
│ └─────────────────┘ └─────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ jms2-03 (JumpServer 堡垒机) │ │
│ │ 49.0.242.25 │ │
│ │ 2vCPU / 4GiB / Ubuntu 24.04 │ │
│ │ 部署节点 (Deployment Node) │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────┐ │
│ │ jms2-04 │ │
│ │ 190.92.231.238 │ │
│ │ 资产节点 │ │
│ └─────────────────┘ │
└─────────────────────────────────────────────────────────────┘
| 主机名 | 公网 IP | 私网 IP | 规格 | 角色 |
|---|---|---|---|---|
| jms2-01 (ecs-f763-0001) | 27.106.107.121 | 192.168.0.102 | c6.large.2 | 资产节点 (Asset Node) |
| jms2-02 (ecs-f763-0002) | 119.12.172.218 | 192.168.0.239 | c6.large.2 | 资产节点 |
| jms2-03 (ecs-f763-0003) | 49.0.242.25 | 192.168.0.88 | c6.large.2 | JumpServer 堡垒机 |
| jms2-04 (ecs-f763-0004) | 190.92.231.238 | 192.168.0.34 | c6.large.2 | 资产节点 |
2.2 软件版本
| 组件 | 版本 | 说明 |
|---|---|---|
| JumpServer | v4.10.16-ce | Community Edition |
| Docker | 29.5.3 | 容器运行时 |
| Docker Compose | v5.1.4 | 容器编排 |
| PostgreSQL | 16.10-bookworm | 元数据数据库 |
| Redis | 7.4.6-bookworm | 缓存与会话 |
| Ubuntu | 24.04 LTS | 操作系统 |
3. 架构设计
3.1 JumpServer 整体架构
┌──────────────────────────────────────────────────────────────────┐
│ Internet │
│ │ │
│ ▼ │
│ ┌──────────────────┐ │
│ │ Nginx (web) │ ← jumpserver/web │
│ │ :80 / :443 │ 端口 80/443 │
│ └────────┬─────────┘ │
│ │ proxy_pass │
│ ┌──────────────┼──────────────┐ │
│ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Core │ │ KoKo │ │ Lion │ │
│ │ :8080 │ │ :2222 │ │ :4822 │ │
│ │ (REST API) │ │ (SSH/Telnet│ │ (RDP/VNC) │ │
│ │ │ │ Proxy) │ │ Web VNC │ │
│ └──────┬──────┘ └─────────────┘ └─────────────┘ │
│ │ │
│ ┌──────┴──────────────────────────────────────┐ │
│ │ Core 内部依赖 │ │
│ │ ┌──────────────┐ ┌──────────────────┐ │ │
│ │ │ PostgreSQL │ │ Redis │ │ │
│ │ │ :5432 │ │ :6379 │ │ │
│ │ │ (Metadata) │ │ (Cache/Session) │ │ │
│ │ └──────────────┘ └──────────────────┘ │ │
│ └──────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
3.2 容器网络拓扑
┌─────────────────────────────────────────────────────────────┐
│ Docker Network: jumpserver (192.168.250.0/24) │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ core │ │ web │ │ koko │ │ lion │ │
│ │ 250.101 │ │ 250.102 │ │ 250.103 │ │ 250.104 │ │
│ └────┬─────┘ └────┬─────┘ └──────────┘ └──────────┘ │
│ │ │ │
│ ┌────┴─────┐ ┌────┴─────┐ │
│ │ postgres │ │ redis │ │
│ │ 250.105 │ │ 250.106 │ │
│ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────┘
说明 :
DOCKER_SUBNET=192.168.250.0/24在.env中配置,避免与宿主机网络冲突。
4. 部署实战
4.1 步骤一:安装 Docker 和 Docker Compose
踩坑提示: 华为云香港区域访问 Docker 官方源不稳定,需使用阿里云镜像加速。
bash
# 1. 安装 Docker (使用阿里云镜像)
curl -fsSL https://get.docker.com | sh -s -- --mirror Aliyun
# 2. 配置 Docker 镜像加速
mkdir -p /etc/docker
cat > /etc/docker/daemon.json << EOF
{
"registry-mirrors": ["https://mirrors.aliyun.com"]
}
EOF
systemctl daemon-reload
systemctl restart docker
systemctl enable docker
# 3. 安装 Docker Compose (阿里云镜像)
curl -L "https://mirrors.aliyun.com/docker-toolbox/linux/compose/releases/download/v2.24.5/docker-compose-$(uname -s)-$(uname -m)" \
-o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
真实服务器输出:
root@jms2-03:~# docker --version
Docker version 29.5.3, build v29.5.3
root@jms2-03:~# docker compose version
Docker Compose version v5.1.4
root@jms2-03:~# docker info | grep -A2 "Registry Mirrors"
Registry Mirrors:
https://mirrors.aliyun.com/
4.2 步骤二:创建 Swap 交换空间
JumpServer 最低要求 4GB 内存,若服务器只有 4GB,必须启用 Swap 防止 OOM (Out of Memory)。
bash
# 创建 4GB Swap 文件
fallocate -l 4G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
# 写入 fstab 开机自动挂载
echo '/swapfile none swap sw 0 0' >> /etc/fstab
# 验证
free -h
真实服务器输出:
root@jms2-03:~# free -h
total used free shared buff/cache available
Mem: 3.8Gi 1.2Gi 285Mi 0.0Ki 2.3Gi 2.4Gi
Swap: 4.0Gi 0B 4.0Gi
4.3 步骤三:拉取 JumpServer 镜像
⚠️ 关键踩坑 : JumpServer v4.x 的 Docker 镜像 不在 Docker Hub ,
jumpserver/core只有 v2.x 标签!v4.x 镜像托管在
registry.cn-beijing.aliyuncs.com/jumpservice。
bash
# ❌ 错误做法 (Docker Hub 上 v4.x 不存在)
docker pull jumpserver/core:v4.10.16-ce # 会报 manifest unknown 错误
# ✅ 正确做法 (从阿里云镜像仓库拉取)
REGISTRY=registry.cn-beijing.aliyuncs.com/jumpservice
docker pull ${REGISTRY}/core:v4.10.16-ce
docker pull ${REGISTRY}/koko:v4.10.16-ce
docker pull ${REGISTRY}/lion:v4.10.16-ce
docker pull ${REGISTRY}/chen:v4.10.16-ce
docker pull ${REGISTRY}/web:v4.10.16-ce
# 重新打标签为 jumpserver/ 前缀 (与 docker-compose.yml 匹配)
docker tag ${REGISTRY}/core:v4.10.16-ce jumpserver/core:v4.10.16-ce
docker tag ${REGISTRY}/koko:v4.10.16-ce jumpserver/koko:v4.10.16-ce
docker tag ${REGISTRY}/lion:v4.10.16-ce jumpserver/lion:v4.10.16-ce
docker tag ${REGISTRY}/chen:v4.10.16-ce jumpserver/chen:v4.10.16-ce
docker tag ${REGISTRY}/web:v4.10.16-ce jumpserver/web:v4.10.16-ce
# 拉取数据库和缓存镜像
docker pull postgres:16.10-bookworm
docker pull redis:7.4.6-bookworm
真实服务器输出 (镜像拉取结果):
REPOSITORY:TAG SIZE CREATED AT
jumpserver/koko:v4.10.16-ce 836MB 2026-03-04 19:49:16
registry.cn-beijing.aliyuncs.com/jumpservice/koko:v4.10.16-ce
836MB
jumpserver/lion:v4.10.16-ce 551MB
jumpserver/chen:v4.10.16-ce 861MB
jumpserver/core:v4.10.16-ce 1.46GB
jumpserver/web:v4.10.16-ce 387MB
postgres:16.10-bookworm 621MB
redis:7.4.6-bookworm 175MB
4.4 步骤四:创建 JumpServer 配置
配置详解 : JumpServer 使用
.env文件驱动docker compose,核心配置来自config.txt模板。
bash
# 创建数据持久化目录
mkdir -p /data/jumpserver
mkdir -p /opt/jumpserver/config
cd /opt/jumpserver
# 生成关键密钥 (重要!迁移时必须保持一致)
SECRET_KEY=$(cat /dev/urandom | tr -dc A-Za-z0-9 | head -c 50)
BOOTSTRAP_TOKEN=$(cat /dev/urandom | tr -dc A-Za-z0-9 | head -c 24)
# 创建 .env 配置文件
cat > /opt/jumpserver/.env << 'EOF'
# ==========
# 镜像配置 (Image Configuration)
# ==========
# 镜像拉取策略: Always=每次都拉取最新, IfNotPresent=本地没有才拉取
IMAGE_PULL_POLICY=IfNotPresent
# ==========
# 安装配置 (Installation Configuration)
# ==========
# 数据持久化目录 (Database persistence directory)
VOLUME_DIR=/data/jumpserver
# 加密密钥 (重要!迁移时必须保持一致)
# Encryption key (CRITICAL! Keep consistent when migrating)
SECRET_KEY=zg8CgJWbDWG66cE09ZV8fanllUR577LS9vJhcDbHRQ7rI0P3OY
# 组件注册 Token (组件间通信认证)
# Component bootstrap token (for inter-component auth)
BOOTSTRAP_TOKEN=vRuuOmXxdP54UplX
# 日志级别: INFO, WARN, ERROR
LOG_LEVEL=ERROR
# Docker 子网 (避免与宿主机网络冲突)
# Docker subnet (avoid conflict with host network)
DOCKER_SUBNET=192.168.250.0/24
# ==========
# 数据库配置 (Database Configuration)
# ==========
DB_ENGINE=postgresql
DB_HOST=postgresql # docker-compose 服务名 (service name)
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=hiRKuPR4HQ6V1QvgRn5V # 必须不含单双引号
DB_NAME=jumpserver
# ==========
# Redis 配置 (Redis Configuration)
# ==========
REDIS_HOST=redis # docker-compose 服务名
REDIS_PORT=6379
REDIS_PASSWORD=JSpb5fwCzSDWc6k3GmQZ # 必须不含单双引号
EOF
配置参数详解
| 参数 | 默认值 | 说明 |
|---|---|---|
SECRET_KEY |
随机生成 | 加密敏感数据 (密码、API Token),迁移时必须保持一致 |
BOOTSTRAP_TOKEN |
随机生成 | KoKo/Lion/Chen 组件注册到 Core 的认证 Token |
VOLUME_DIR |
/data/jumpserver |
挂载卷目录,存储录像、任务日志、数据库备份 |
DOCKER_SUBNET |
192.168.250.0/24 |
JumpServer 内部容器网络,避免与现有网络冲突 |
DB_PASSWORD |
- | 不能包含单引号或双引号,否则 PostgreSQL 启动失败 |
REDIS_PASSWORD |
- | 不能包含单引号或双引号,否则 Redis 启动失败 |
LOG_LEVEL |
ERROR |
生产环境建议 ERROR,排查问题时临时改为 INFO |
4.5 步骤五:启动 JumpServer
bash
# 创建 docker-compose.yml (手动编写,因为 jmsctl.sh install 会卡住)
# 实际部署时使用 JumpServer 自带的 compose 文件
cd /opt/jumpserver
# 启动所有服务 (首次启动会自动初始化数据库,约 2-3 分钟)
docker compose \
--env-file .env \
-f compose/network.yml \
-f compose/redis.yml \
-f compose/postgres.yml \
-f compose/core.yml \
-f compose/koko.yml \
-f compose/lion.yml \
-f compose/chen.yml \
-f compose/web.yml \
up -d
# 查看启动状态
docker compose -f compose/core.yml ps
真实服务器输出 (所有容器状态):
NAMES IMAGE STATUS PORTS
jms_postgresql postgres:16.10-bookworm Up 10 minutes (healthy) 5432/tcp
jms_redis redis:7.4.6-bookworm Up 10 minutes (healthy) 6379/tcp
jms_web jumpserver/web:v4.10.16-ce Up 10 minutes (healthy) 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp
jms_lion jumpserver/lion:v4.10.16-ce Up 10 minutes (healthy) 4822/tcp, 8081/tcp
jms_core jumpserver/core:v4.10.16-ce Up 10 minutes (healthy) 8080/tcp
jms_chen jumpserver/chen:v4.10.16-ce Up 10 minutes (healthy) 8082/tcp
jms_koko jumpserver/koko:v4.10.16-ce Up 9 minutes (healthy) 0.0.0.0:2222->2222/tcp
✅ 所有容器状态均为
(healthy)表示启动成功!
5. 踩坑记录
5.1 坑一:Docker Hub 上没有 JumpServer v4.x 镜像
现象:
bash
docker pull jumpserver/core:v4.10.16-ce
# Error: manifest unknown: manifest unknown
原因: JumpServer v4.x 开始,官方镜像不再推送到 Docker Hub,只保留 v2.x 历史版本。
解决方案: 从阿里云镜像仓库拉取:
bash
docker pull registry.cn-beijing.aliyuncs.com/jumpservice/core:v4.10.16-ce
docker tag registry.cn-beijing.aliyuncs.com/jumpservice/core:v4.10.16-ce jumpserver/core:v4.10.16-ce
5.2 坑二:DOCKER_IMAGE_MIRROR 配置误解
现象 : 在 .env 中配置了 DOCKER_IMAGE_MIRROR=1,但 JumpServer 镜像依然拉取失败。
原因 : DOCKER_IMAGE_MIRROR 只影响 Docker/Compose 二进制文件下载 ,不影响 JumpServer 镜像拉取。镜像拉取使用的是 REGISTRY 变量(在 compose/core.yml 等文件中定义)。
解决方案 : 手动拉取镜像后打标签,或修 compose/*.yml 文件中的镜像地址。
5.3 坑三:jmsctl.sh install 卡住
现象 : 执行 jmsctl.sh install 后脚本卡在检测 Docker 版本步骤,无输出。
原因 : jmsctl.sh 会检测网络环境并尝试拉取镜像,在华为云香港区域网络不稳定时会超时卡死。
解决方案 : 手动创建 .env 文件,跳过 jmsctl.sh,直接执行 docker compose up -d。
5.4 坑四:SSH heredoc 远程执行异常
现象 : 通过 SSH 远程执行 cat > file << EOF ... EOF 时,变量被展开或格式错乱。
原因: SSH 远程执行时,Shell 会对 heredoc 内容进行变量展开。
解决方案 : 使用 cat > file << 'EOF'(单引号包裹 EOF)禁止变量展开,或使用 echo 逐行写入。
6. Bug 修复:ERR_INVALID_REDIRECT
6.1 问题描述
部署完成后,浏览器访问 http://49.0.242.25/ 显示:
This site cannot be reached
ERR_INVALID_REDIRECT
6.2 根因分析
查看 jms_web 容器内的 Nginx 配置文件 /etc/nginx/conf.d/https_server.conf:
nginx
server {
listen 80;
# server_name demo.example.com; ← 被注释了!
location / {
return 307 https://$server_name$request_uri; ← 问题所在!
}
}
问题链:
server_name 被注释
↓
$server_name 变量为空 (evaluates to empty string)
↓
return 307 https://$server_name$request_uri;
↓
实际重定向到: https:/// ← 空主机名!
↓
浏览器报错: ERR_INVALID_REDIRECT
6.3 修复方案
将 80 端口的 location / 从 307 重定向 改为 直接反向代理到后端。
修复后的配置:
nginx
server {
listen 80;
location /.well-known/ {
proxy_pass http://http_server;
}
location / {
# ✅ 直接代理到后端,不再重定向
proxy_pass http://http_server;
# 以下是标准 WebSocket 代理配置
proxy_buffering off;
proxy_request_buffering off;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
proxy_set_header X-Forwarded-For $remote_addr;
# 超时配置 (单位: 秒)
proxy_ignore_client_abort on;
proxy_connect_timeout 600;
proxy_send_timeout 600;
proxy_read_timeout 600;
send_timeout 6000;
}
}
6.4 修复步骤 (真实命令)
bash
# 1. 在宿主机上写入修复后的配置 (绕过 SSH heredoc 问题)
cat > /tmp/jms_https_fix.conf << 'CONFEOF'
# 完整配置内容 (见上方)
...
CONFEOF
# 2. 复制到容器
docker cp /tmp/jms_https_fix.conf jms_web:/etc/nginx/conf.d/https_server.conf
# 3. 测试配置
docker exec jms_web nginx -t
# 4. 重载 Nginx (不中断现有连接)
docker exec jms_web nginx -s reload
修复后验证:
bash
curl -sI http://localhost:80/
# HTTP/1.1 200 OK ← 修复成功!
curl -s http://localhost:80/api/health/
# {"status":true,"db_status":true,"db_time":0.0026,"redis_status":true}
7. 验证测试
7.1 Web 界面访问
访问地址: <ADDRESS_REMOVED>
默认账号: admin / admin
⚠️ 安全提醒: 首次登录后请立即修改默认密码!
7.2 API 健康检查
bash
curl http://49.0.242.25/api/health/
预期输出:
json
{
"status": true,
"db_status": true,
"db_time": 0.002639293670654297,
"redis_status": true,
"redis_time": 0.0002593994140625,
"time": 1780831762
}
| 字段 | 说明 |
|---|---|
status |
整体健康状态 |
db_status |
PostgreSQL 连接状态 |
db_time |
数据库查询耗时 (秒) |
redis_status |
Redis 连接状态 |
redis_time |
Redis PING 耗时 (秒) |
7.3 端口检测
bash
# Web 界面
telnet 49.0.242.25 80
# SSH 资产连接 (通过 JumpServer KoKo 组件)
ssh -p 2222 admin@49.0.242.25
8. 总结
8.1 部署要点回顾
┌─────────────────────────────────────────────────────────────────────┐
│ JumpServer 部署 Checklist │
│ │
│ ✅ Docker + Compose 安装 (配置阿里云镜像加速) │
│ ✅ Swap 空间创建 (内存 ≤ 4GB 必须) │
│ ✅ 从 registry.cn-beijing.aliyuncs.com 拉取 v4.x 镜像 │
│ ✅ 手动创建 .env 配置 (跳过 jmsctl.sh) │
│ ✅ 检查 SECRET_KEY/BOOTSTRAP_TOKEN 不含特殊字符 │
│ ✅ 修复 https_server.conf 中 80 端口重定向 Bug │
│ ✅ 验证所有容器 healthy + API 健康检查通过 │
│ │
└─────────────────────────────────────────────────────────────────────┘
8.2 常见问题速查表
| 问题 | 原因 | 解决方案 |
|---|---|---|
manifest unknown |
Docker Hub 无 v4.x 镜像 | 从阿里云镜像仓库拉取 |
jmsctl.sh 卡住 |
网络超时 | 手动创建 .env + docker compose up |
ERR_INVALID_REDIRECT |
server_name 为空导致重定向到 https:/// |
修改 https_server.conf,将 80 端口改为 proxy_pass |
容器 unhealthy |
DB/Redis 密码含特殊字符 | 密码不能包含单引号或双引号 |
| 登录后空白页 | Nginx 代理配置错误 | 检查 proxy_set_header 配置 |
8.3 下一步
- 添加
jms2-01/0002/0004为资产 (Asset) - 创建用户并配置资产授权 (Authorization)
- 测试 SSH 和 RDP 会话录制功能
- 配置 LDAP/AD 统一认证
- 启用 HTTPS (配置可信 SSL 证书)
作者: LiaCin | 最后更新: 2026-06-07 | JumpServer v4.10.16-ce