code-server 多用户隔离指南:N 人共享一台机器
【免费下载链接】code-serverVS Code in the browser项目地址: https://gitcode.com/GitHub_Trending/co/code-server
同一个 code-server 实例给整个团队用时,配置文件互相覆盖、扩展越装越乱、权限边界形同虚设。本文给出一条基于 Unix 用户的隔离路径:每人一个独立进程,按 4 个阶段从 0 搭到可上线,并附踩坑记录与检查清单。
先想清楚:哪种隔离策略适合你的团队
三种常见路子:KVM 级虚机、每用户一个 Docker 容器、每用户一个 Unix 账户加独立进程。
| 方案 | 隔离强度 | 内存开销 | 运维复杂度 |
|---|---|---|---|
| KVM 虚机 | 最强 | 极高(每用户数百 MB 起) | 高 |
| Docker 容器 | 强 | 中 | 中(镜像、存储、编排都要管) |
| Unix 用户 + 独立进程 | 中(够用) | 低 | 低,全靠系统原生命令 |
选 Unix 用户方案的理由很直接:code-server 是单用户设计,天然一进程一环境,用系统原生的用户、文件权限、systemd 资源限额就能划清边界,不需要学一套容器编排。代价是隔离强度弱于容器——内核漏洞、恶意node_modules这类场景它管不住。适用边界:≤30 人的内部团队、彼此基本可信。对外提供服务,或需要内核级隔离,请直接上容器方案。
code-server 多用户隔离架构速览
整条链路四段:浏览器 → Nginx(子路径路由 + TLS 终结)→ 每个用户一个独立 code-server 进程 → 各自的隔离数据目录。每个实例只监听127.0.0.1上的专属端口,对外唯一的入口就是 Nginx 的子路径:
每个实例的工作目录、用户数据、扩展目录都圈在自己的 Unix 账户里,实例之间互相不可读。
阶段一:打地基——装好运行环境与隔离的根目录
用官方安装脚本装一份系统级 code-server,再为多租户数据预留独立根目录,并建一个只记录「用户 → 端口」的映射文件(后面路由阶段靠它取端口):
sh install.sh # 仓库自带的官方安装脚本 mkdir -p /var/lib/code-server /etc/nginx/snippets # 端口映射文件,一行一个:用户名 端口 touch /var/lib/code-server/ports.map阶段二:给每个开发者开独立实例
给每个用户建系统账户、生成专属配置、挂一个带资源限额的 systemd 实例。端口不要靠 UID 推导——UID 空间和普通用户重叠,迟早撞车,所以随机取端口并登记进映射文件:
#!/usr/bin/env bash # /usr/local/bin/cs-open-account set -euo pipefail NAME="$1" DIR=/var/lib/code-server/"$NAME" PORT=$(shuf -i 9000-9999 -n 1) useradd -r -m -d "$DIR" -s /bin/bash "codesrv-$NAME" sudo -u "codesrv-$NAME" bash -c " mkdir -p $DIR/projects $DIR/.config/code-server cat > $DIR/.config/code-server/config.yaml <<EOF bind-addr: 127.0.0.1:$PORT auth: password password: \$(openssl rand -hex 16) cert: false user-data-dir: $DIR/.local/share/code-server extensions-dir: $DIR/.local/share/code-server/extensions EOF chmod 600 $DIR/.config/code-server/config.yaml" echo "$NAME $PORT" >> /var/lib/code-server/ports.mapsystemd 模板保证每个实例跑在自己的账户里,顺带压住资源上限:
# /etc/systemd/system/code-server@.service [Unit] Description=code-server instance %i After=network.target [Service] User=codesrv-%i WorkingDirectory=/var/lib/code-server/%i/projects ExecStart=/usr/local/bin/code-server \ --config /var/lib/code-server/%i/.config/code-server/config.yaml \ --abs-proxy-base-path /users/%i CPUQuota=50% MemoryMax=1G TasksMax=512 Restart=always注意--abs-proxy-base-path:子路径部署时内置端口代理(/proxy/端口/)依赖它才能算对地址,漏配就是后面要复盘的坑 2。建完用户执行systemctl daemon-reload && systemctl enable --now code-server@名字即可拉起。
阶段三:接流量——Nginx 按子路径分发到对应端口
给每个用户生成一段固定端口的 location(比在 Nginx 里现算变量稳得多),脚本从映射文件取端口:
# /usr/local/bin/cs-proxy-snippet <用户名>,输出对应 location 片段 NAME="$1"; PORT=$(awk -v n="$NAME" '$1==n{print $2}' /var/lib/code-server/ports.map) cat <<EOF location /users/$NAME/ { proxy_pass http://127.0.0.1:$PORT/; proxy_http_version 1.1; proxy_set_header Upgrade \$http_upgrade; proxy_set_header Connection "upgrade"; 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; } EOF把片段 include 进站点配置,nginx -t通过后 reload;TLS 在 Nginx 层终结,各实例只管 127.0.0.1,永远不对公网暴露端口。
阶段四:上保险——收权限、挡 SSH、留审计
# 1. 禁止这批账户 SSH 登录 echo 'DenyUsers codesrv-*' >> /etc/ssh/sshd_config && systemctl reload sshd # 2. 数据目录整体收紧权限,防止组内互读 find /var/lib/code-server -user codesrv-* -type d -exec chmod 700 {} + find /var/lib/code-server -user codesrv-* -type f -exec chmod 600 {} + # 3. 对数据根目录挂审计规则 auditctl -w /var/lib/code-server -p rwxa -k cs-access密码写在各用户的config.yaml里,所以该文件必须保持 600,阶段四的 find 会把已放宽的权限重新收回来。
踩坑实录:四条都是真实事故
- 现象:页面能打开、刷新一次就白屏。原因:代理层没转发 WebSocket Upgrade 头。解法:location 里补
Upgrade/Connection两行。 - 现象:子路径下内置端口代理
/proxy/3000全部 404。原因:code-server 不知道自己挂在子路径里。解法:启动参数加--abs-proxy-base-path并与代理路径对齐。 - 现象:A 登进去却看到 B 的项目。原因:端口分配撞车,A 的代理指向了 B 的端口。解法:端口随机生成后登记映射文件,创建前查重。
- 现象:有用户直接
cat到了别人的登录密码。原因:config.yaml默认权限组可读。解法:生成时chmod 600,并定期复检。
上线前检查清单
| 检查项 | 通过标准 |
|---|---|
| 各实例端口唯一 | 端口映射文件无重复端口 |
| 实例仅监听回环地址 | ss -tlnp见 127.0.0.1,无 0.0.0.0 |
--abs-proxy-base-path | 与 Nginx 子路径逐字一致 |
| WebSocket 代理头 | 终端、Git 扩展实测可用 |
| 资源限额 | systemd 中MemoryMax/CPUQuota已生效 |
| 目录权限 | 用户目录 700、配置 600 |
| SSH 收口 | codesrv-*登录被拒 |
| 审计规则 | auditctl -l含 cs-access 规则 |
清单全绿后再开第二个用户。接下来值得继续挖的两个方向:用反向代理层的 SSO 替换各实例的独立密码,以及把整套模板搬到 Kubernetes 做按需弹性伸缩。
【免费下载链接】code-serverVS Code in the browser项目地址: https://gitcode.com/GitHub_Trending/co/code-server
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考