Jupyter notebook 容器内服务器多用户管理方法
-
- 一、问题背景与目标
- 二、用户与目录准备
- 三、安装并配置 Code-Server(多用户版)
- 四、安装并启用 JupyterLab 与 `jupyter-server-proxy`
- 五、为 JupyterLab 配置「允许代理的端口」
- 六、访问 Code-Server:通过 `/proxy/<port>/` 路径
- 七、关闭 Code-Server 密码验证(可选)
- 八、让 JupyterLab 持续运行:避免关闭终端导致服务中断
- 九、完整命令流程汇总(以时间顺序罗列,供备份)
- 十、常见故障 & 排查思路
- 十一、完整流程回顾(命令清单)
-
- 关键思路和解决要点
- 十二、快速故障排查清单
-
- 总结
以下是你从头到尾处理“在容器中给多位用户分别开 Code-Server(VS Code Web IDE),并通过 JupyterLab 做反向代理到不同端口”这件事的完整思路、问题、解决方案和关键命令。你可以把它当作模板,留作日后在类似场景下的参考。
一、问题背景与目标
环境
- 你只有一个容器的最高权限(root),无法接触到物理机或云主机的操作台。
- 容器里可以运行 JupyterLab(被映射到外部某个端口,比如主机的 23528)并通过它提供的终端进行所有操作。
- 容器里已有 10 个普通用户(test1、test2 … test10),每个用户都有自己的 Linux 登录密码。
目标
- 给每个用户提供一个独立的 VS Code Web IDE(Code-Server)实例,类似多用户在物理机器上分别登录并各自拥有一个 VS Code 界面。
- 不想让用户互相干扰:每个用户只能看到并操作自己家目录下的内容。
- 要让外部(浏览器)通过一个统一入口访问。既不想让物理机直接开放 8881~8890 等端口,也不想给每个人单独配置 SSH+端口转发。
- 最终方式:在容器里启动十路 Code-Server,分别监听 8881,…,8890;再在同一个容器里的 JupyterLab 上启用 jupyter-server-proxy,把浏览器访问 /proxy/8881/ ~ /proxy/8890/ 的请求,反向代理到对应用户的 Code-Server。
主要问题
- 容器里只有 root 用户才可安装/配置,但希望让普通用户(test1…test10)各自运行各自的 Code-Server。
- 每台 Code-Server 默认会绑定到 127.0.0.1:8080 或者随机端口,需要改成“按用户分配端口”并保持不变。
- JupyterLab 默认监听 8888(或 8889),与 Code-Server 的某些端口冲突,必须改一个空闲的端口启动。
- JupyterLab 默认不允许 root 直接运行,得加 –allow-root。
- 即使安装了 jupyter-server-proxy,也要告诉它“允许代理哪些端口”,才可通过 /proxy/<port>/ 访问。
二、用户与目录准备
假设你已经让运维/管理员帮你在容器里创建好了 10 个用户 test1…test10,并且各用户都通过 passwd testX 设置了一个登录密码。示例(root 身份):
for U in test1 test2 test3 test4 test5 test6 test7 test8 test9 test10; do
id "$U" &>/dev/null || useradd -m -s /bin/bash "$U"
echo "$U:someStrongPassword" | chpasswd
done
这保证了 /home/test1、/home/test2 … /home/test10 这 10 个家目录都存在,每个用户都能通过 su – testX 切换过去。
三、安装并配置 Code-Server(多用户版)
安装 Code-Server 以 root 身份在容器里安装最新版 Code-Server(以下版本号仅供示例,按需改):
# 下载并安装
curl -fsSL https://code-server.dev/install.sh | sh
安装完成后,通过 which code-server 验证:
which code-server
# 例如会输出:/usr/bin/code-server
为每个用户指定一个固定端口启动 Code-Server 我们约定:
- test1 → 监听 127.0.0.1:8881
- test2 → 监听 127.0.0.1:8882
- …
- test10 → 监听 127.0.0.1:8890
写一个简单的启动脚本,比如 /usr/local/bin/start-all-code-servers.sh,内容如下:
#!/bin/bash
#
# start-all-code-servers.sh
# 以 root 身份运行,依次为 test1~test10 启动 code-server 实例,端口 8881~8890。
#
USERS=( test1 test2 test3 test4 test5 test6 test7 test8 test9 test10 )
BASE_PORT=8881
for idx in "${!USERS[@]}"; do
USER="${USERS[$idx]}"
PORT=$(( BASE_PORT + idx ))
HOME_DIR="/home/${USER}"
USER_DATA_DIR="${HOME_DIR}/.local/share/code-server"
EXT_DIR="${HOME_DIR}/.local/share/code-server/extensions"
LOG_FILE="${HOME_DIR}/code-server.log"
# 确保家目录和目标目录存在
mkdir -p "${USER_DATA_DIR}" "${EXT_DIR}"
chown -R "${USER}:${USER}" "$(dirname "${USER_DATA_DIR}")"
# 杀掉可能残留的同端口 old process
ss -ltnp | grep ":${PORT} " &>/dev/null && \\
pkill -f "code-server.*:${PORT}"
echo "▶ 为用户 ${USER} 启动 code-server,监听端口 ${PORT} …"
su – "$USER" -c "\\
nohup code-server \\
–auth password \\ # 先用“密码验证”,后面可改成 none
–bind-addr 127.0.0.1:${PORT} \\
–user-data-dir \\"${USER_DATA_DIR}\\" \\
–extensions-dir \\"${EXT_DIR}\\" \\
\\"${HOME_DIR}\\" \\
> \\"${LOG_FILE}\\" 2>&1 &\\
"
done
echo "✅ 所有 Code-Server 实例启动命令已发出,请稍后检查端口监听情况。"
执行并确认:
chmod +x /usr/local/bin/start-all-code-servers.sh
/usr/local/bin/start-all-code-servers.sh
验证 Code-Server 是否在指定端口监听 等几秒后,用以下命令查看 8881~8890 是否都被 code-server 占用:
ss -ltnp | grep "888[1-9]\\|8890"
预期输出示例(每行代表一个 code-server 进程):
LISTEN 0 128 127.0.0.1:8881 0.0.0.0:* users:(("code-server",pid=1234,fd=…))
LISTEN 0 128 127.0.0.1:8882 …
…
LISTEN 0 128 127.0.0.1:8890 …
默认密码配置
- 默认 –auth password 会让 code-server 在 ~/·.config/code-server/config.yaml 里生成一行 password: <hashed>(已哈希)。
- 终端会提示“Please log in below. Check the config file at /home/testX/.config/code-server/config.yaml for the password.”
- 如果日后想让用户直接免密码登录,可参考后续章节“关闭 Code-Server 密码验证”。
四、安装并启用 JupyterLab 与 jupyter-server-proxy
确认容器里已有 JupyterLab 如果没有,就先安装:
# 比如使用 pip 安装最新 JupyterLab
pip install jupyterlab
安装 jupyter-server-proxy 你需要在运行 JupyterLab 的那个 Python/Conda 环境中执行:
pip install jupyter-server-proxy
安装完成后确认:
pip show jupyter-server-proxy
# 输出类似:
# Name: jupyter_server_proxy
# Version: 4.4.0
# Location: /opt/conda/lib/python3.11/site-packages
启用 server extension 仍然在同一个环境下,执行:
jupyter server extension enable –sys-prefix jupyter_server_proxy
如果输出:
Enabling: jupyter_server_proxy
– Writing config: /opt/conda/etc/jupyter
– Validating jupyter_server_proxy…
jupyter_server_proxy 4.4.0 OK
– Extension successfully enabled.
就表示启用成功。
验证扩展启用状态
jupyter server extension list
你应该看到:
Config dir: /opt/conda/etc/jupyter
jupyter_server_proxy enabled
– Validating jupyter_server_proxy…
jupyter_server_proxy 4.4.0 OK
jupyterlab enabled
– Validating jupyterlab…
jupyterlab 4.4.3 OK
…(其余扩展)…
五、为 JupyterLab 配置「允许代理的端口」
既然你要让 JupyterLab 负责把 /proxy/8881/~/proxy/8890/ 这些路径反代到各自的 code-server,就必须把这些端口写到 JupyterLab 的放行列表里:
在环境级配置目录下创建 proxy-allowed-ports.json JupyterLab 4.x 会去读取 /opt/conda/etc/jupyter/jupyter_server_config.d/ 里的所有 .json 配置,来调整它的运行行为。执行:
mkdir -p /opt/conda/etc/jupyter/jupyter_server_config.d
cat > /opt/conda/etc/jupyter/jupyter_server_config.d/proxy-allowed-ports.json << 'EOF'
{
"ServerProxy": {
"allowed_ports": [8881,8882,8883,8884,8885,8886,8887,8888,8889,8890]
}
}
EOF
这会把 8881~8890 全部加入“允许被代理”的名单中。
重启 JupyterLab
# 假设之前没启动,或当前已经停止,只要执行:
jupyter lab –ip=0.0.0.0 –port=8900 –allow-root
解释:
- –ip=0.0.0.0:让容器对外网可访问
- –port=8900:指定一个与 code-server 端口不冲突的空闲端口
- –allow-root:因为你是以 root 身份运行 JupyterLab,必须加,否则它会拒绝启动
启动成功后,你会看到:
[I …] ServerApp] jupyter_server_proxy | extension was successfully loaded.
[I …] LabApp] Listening on http://0.0.0.0:8900/lab?token=<token>
这就说明:
确认 JupyterLab 实际运行 你可以在同一个终端里再开一个面板,执行:
ss -ltnp | grep 8900
应显示:
LISTEN 0 128 0.0.0.0:8900 0.0.0.0:* users:(("python",pid=…,fd=…))
这就证明 JupyterLab 确实在跑。
六、访问 Code-Server:通过 /proxy/<port>/ 路径
至此,后端每个用户的 Code-Server 已经都在 127.0.0.1:8881~8890 上“各自独立运行”,前端的 JupyterLab 也在 0.0.0.0:8900 上对外承载。外网和浏览器的访问路径示例为:
-
JupyterLab 主界面(Token 登录)
http://<宿主机IP或域名>:<映射后的端口>/lab?token=<jupyter-token>
例如:
http://36.151.192.85:23528/lab?token=24fd261e7388848b7bae6bb10f8af2bcf909a06fc57b5a96
-
不用进入 JupyterLab UI 就直接访问 test1 的 Code-Server
http://36.151.192.85:23528/proxy/8881/
- 访问时,先到 JupyterLab(容器 8900),“Server Proxy” 插件自动把 /proxy/8881/ 转发到 127.0.0.1:8881(test1 的 Code-Server)。
- Code-Server 自动弹出登录框,要求输入 test1 的系统密码(除非之后你主动关闭了密码验证)。
- 登录成功后,就直接进入 test1 的 VS Code Web IDE,默认工作目录 /home/test1。
-
如果想让用户打开时直接定位到自己的家目录(可选) 在 URL 末尾加上 ?folder=/home/test1:
http://36.151.192.85:23528/proxy/8881/?folder=/home/test1
这样 Code-Server 就会打开 /home/test1 目录,而不是默认路径。
-
test2 ~ test10 的访问方法完全类推:
http://36.151.192.85:23528/proxy/8882/?folder=/home/test2
…
http://36.151.192.85:23528/proxy/8890/?folder=/home/test10
七、关闭 Code-Server 密码验证(可选)
如果你不想每次都去家目录下看密码,让用户无痛直接进入(适用于私有网络、信任环境),可在每个用户的 config 文件里将认证方式改为 none,或者在启动命令中加 –auth none 覆盖。
修改 config.yaml(永久方案) 以 testX 为例,打开:
vi /home/testX/.config/code-server/config.yaml
把内容改为:
bind-addr: 127.0.0.1:888X
auth: none
cert: false
# (无需保留 password 行,可以删掉或注释)
保存后,重启该用户的 code-server 实例即可:
su – testX -c "pkill -f 'code-server.*:888X'"
su – testX -c "nohup code-server –auth none –bind-addr 127.0.0.1:888X /home/testX > /home/testX/code-server.log 2>&1 &"
这样,访问 /proxy/888X/ 时就不会再出现登录框,直接进入 VS Code 界面。
用命令行参数覆盖(临时/快速方案) 如果你不想动 config.yaml,也可以在启动脚本直接写:
su – testX -c "\\
nohup code-server \\
–auth none \\
–bind-addr 127.0.0.1:888X \\
–user-data-dir /home/testX/.local/share/code-server \\
–extensions-dir /home/testX/.local/share/code-server/extensions \\
/home/testX \\
> /home/testX/code-server.log 2>&1 &\\
"
启动后同样不会再弹登录框。
八、让 JupyterLab 持续运行:避免关闭终端导致服务中断
如你最后所提到的,如果直接在终端里运行:
jupyter lab –ip=0.0.0.0 –port=8900 –allow-root
一旦关闭该终端(或按 Ctrl+C),JupyterLab 后端就会退出。为确保代理一直在线,可以采用下面两种常用方式之一:
使用 nohup + & 把 JupyterLab 放后台运行
nohup jupyter lab –ip=0.0.0.0 –port=8900 –allow-root \\
> /var/log/jupyterlab.log 2>&1 &
-
这条命令会把所有日志输出到 /var/log/jupyterlab.log,并把进程放到后台。
-
之后你就可以安全地关闭当前终端,JupyterLab 仍然继续运行。
-
查看日志可用:
tail -f /var/log/jupyterlab.log
使用 tmux 或 screen 保持会话
-
如果容器里有 tmux:
tmux new -s jlab
# 此时会打开一个 tmux 会话
jupyter lab –ip=0.0.0.0 –port=8900 –allow-root
# 启动后按 Ctrl+B 然后按 D,将该会话“detach”到后台 -
即便你退出 SSH 或关闭显示终端,tmux 会话和其中的 JupyterLab 都会继续运行。
-
下次想查看或停止它,用:
tmux attach -t jlab
Ctrl+C # 停止 JupyterLab
九、完整命令流程汇总(以时间顺序罗列,供备份)
以下示例假设容器里所有操作都在同一个 shell 或脚本里执行。请结合你的实际用户列表、路径、端口,按需改动。
创建 test1…test10 用户(可选,若已有人就跳过)
for U in test1 test2 test3 test4 test5 test6 test7 test8 test9 test10; do
id "$U" &>/dev/null || useradd -m -s /bin/bash "$U"
echo "$U:yourStrongPassword" | chpasswd
done
安装 code-server
curl -fsSL https://code-server.dev/install.sh | sh
# 验证
which code-server
编写“启动所有 code-server”的脚本
cat > /usr/local/bin/start-all-code-servers.sh << 'EOF'
#!/bin/bash
USERS=( test1 test2 test3 test4 test5 test6 test7 test8 test9 test10 )
BASE_PORT=8881
for idx in "${!USERS[@]}"; do
USER="${USERS[$idx]}"
PORT=$(( BASE_PORT + idx ))
HOME_DIR="/home/${USER}"
DATA_DIR="${HOME_DIR}/.local/share/code-server"
EXT_DIR="${HOME_DIR}/.local/share/code-server/extensions"
LOG="${HOME_DIR}/code-server.log"
mkdir -p "${DATA_DIR}" "${EXT_DIR}"
chown -R "${USER}:${USER}" "${HOME_DIR}/.local/share"
# 杀掉占用同端口的进程
ss -ltn | grep ":${PORT} " &>/dev/null && pkill -f "code-server.*:${PORT}"
echo "▶ 启动 ${USER} 的 code-server,端口 ${PORT}"
su – "$USER" -c "\\
nohup code-server \\
–auth password \\
–bind-addr 127.0.0.1:${PORT} \\
–user-data-dir \\"${DATA_DIR}\\" \\
–extensions-dir \\"${EXT_DIR}\\" \\
\\"${HOME_DIR}\\" \\
> \\"${LOG}\\" 2>&1 &\\
"
done
echo "✅ 所有 code-server 启动命令已发出"
EOF
chmod +x /usr/local/bin/start-all-code-servers.sh
/usr/local/bin/start-all-code-servers.sh
验证 Code-Server 是否在 8881~8890 端口监听
ss -ltnp | grep "888[1-9]\\|8890"
你会看到 10 行对应的 code-server 监听信息。
安装并启用 jupyter-server-proxy
pip install –no-cache-dir jupyter-server-proxy
jupyter server extension enable –sys-prefix jupyter_server_proxy
jupyter server extension list | grep proxy
# 确保输出里有 jupyter_server_proxy enabled
创建“允许代理端口”配置
mkdir -p /opt/conda/etc/jupyter/jupyter_server_config.d
cat > /opt/conda/etc/jupyter/jupyter_server_config.d/proxy-allowed-ports.json << 'EOF'
{
"ServerProxy": {
"allowed_ports": [8881,8882,8883,8884,8885,8886,8887,8888,8889,8890]
}
}
EOF
启动 JupyterLab(绑定到 8900,允许 root) 方法 A:占据前台(要保留终端不关)
jupyter lab –ip=0.0.0.0 –port=8900 –allow-root
方法 B:用 nohup & 放后台
nohup jupyter lab –ip=0.0.0.0 –port=8900 –allow-root \\
> /var/log/jupyterlab.log 2>&1 &
# 检查日志
tail -n 20 /var/log/jupyterlab.log
方法 C:用 tmux/screen
tmux new -s jlab
# 在 tmux 里执行:
jupyter lab –ip=0.0.0.0 –port=8900 –allow-root
# JupyterLab 启动后,按 Ctrl+B D,detach 掉会话。
在外部浏览器访问 JupyterLab
http://<宿主机IP或域名>:<映射后的端口>/lab?token=<输出日志的 token>
例如如果容器的 8900 被映射到主机 23528,就用:
http://36.151.192.85:23528/lab?token=….
访问每个用户的 Code-Server
-
test1(端口 8881)
http://36.151.192.85:23528/proxy/8881/
(或带目录参数:…/proxy/8881/?folder=/home/test1) 输入 test1 的系统密码登录,即可看到 /home/test1。
-
test2(端口 8882)
http://36.151.192.85:23528/proxy/8882/
-
…
-
test10(端口 8890)
http://36.151.192.85:23528/proxy/8890/
依次输入各自的用户密码,登录成功就进入对应家目录的 VS Code Web IDE。
(可选)关闭 Code-Server 密码登录
-
修改 config.yaml 方案
vi /home/testX/.config/code-server/config.yaml
改为:
bind-addr: 127.0.0.1:888X
auth: none
cert: false然后重启该用户的 code-server:
su – testX -c "pkill -f 'code-server.*:888X'"
su – testX -c "nohup code-server –auth none –bind-addr 127.0.0.1:888X /home/testX > /home/testX/code-server.log 2>&1 &" -
命令行参数覆盖方案 如果你不想编辑 config.yaml,直接在启动脚本里:
su – testX -c "\\
nohup code-server \\
–auth none \\
–bind-addr 127.0.0.1:888X \\
/home/testX \\
> /home/testX/code-server.log 2>&1 &\\
"
十、常见故障 & 排查思路
JupyterLab 无法启动,提示端口被占
-
原因:8888、8889、8890 都已被 Code-Server 占用。
-
解决:改用一个空闲端口(如 8900、9000)启动 JupyterLab:
jupyter lab –ip=0.0.0.0 –port=8900 –allow-root
JupyterLab 启动后看不到“🔗 Server Proxy”图标
-
检查扩展是否启用:
jupyter server extension list | grep proxy
-
确认 JupyterLab 版本 ≥ 3.0(你的是 4.4.3,所以不用做前端 build)。
-
确认你是以同一个 Python/Conda 环境启动,而且 pip show jupyter-server-proxy 显示正确路径。
-
如果一直不见,可跳过 UI,直接用“放行端口”配置(见上文“允许代理端口”那节)。
访问 /proxy/8881/ 报 404 或 502
-
检查 JupyterLab 是否在运行且端口正确:
ss -ltnp | grep 8900
确保有进程在 0.0.0.0:8900 监听。
-
检查 proxy-allowed-ports.json 是否放在 /opt/conda/etc/jupyter/jupyter_server_config.d/ 且内容正确。
-
确认 Code-Server 实例确实在 127.0.0.1:8881 监听:
ss -ltnp | grep 8881
-
如果 Code-Server 绑定到了 8080 而不是 8881,就会代理失败,需要修改 Code-Server 的 –bind-addr。
Code-Server 启动后不在指定端口监听
- 原因可能是命令行参数里没有加 –bind-addr,或者 config.yaml 里还写着 127.0.0.1:8080。
- 解决:在启动脚本里务必加 –bind-addr 127.0.0.1:888X,或把 ~/.config/code-server/config.yaml 中的 bind-addr 改为 127.0.0.1:888X。
关闭终端后 JupyterLab 停止
-
必须让 JupyterLab 以后台或守护进程方式运行:
-
nohup + &:
nohup jupyter lab –ip=0.0.0.0 –port=8900 –allow-root > /var/log/jupyterlab.log 2>&1 &
-
tmux/screen:
tmux new -s jlab
# 在 tmux 会话里运行 jupyter lab … ,然后 Ctrl+B + D detach
-
十一、完整流程回顾(命令清单)
# 一、(可选)创建 test1~test10 用户
for U in test1 test2 test3 test4 test5 test6 test7 test8 test9 test10; do
id "$U" &>/dev/null || useradd -m -s /bin/bash "$U"
echo "$U:StrongPassword123" | chpasswd
done
# 二、安装 code-server
curl -fsSL https://code-server.dev/install.sh | sh
# 三、编写并运行“启动所有 code-server”的脚本
cat > /usr/local/bin/start-all-code-servers.sh << 'EOF'
#!/bin/bash
USERS=( test1 test2 test3 test4 test5 test6 test7 test8 test9 test10 )
BASE_PORT=8881
for idx in "${!USERS[@]}"; do
USER="${USERS[$idx]}"
PORT=$(( BASE_PORT + idx ))
HOME_DIR="/home/${USER}"
DATA_DIR="${HOME_DIR}/.local/share/code-server"
EXT_DIR="${HOME_DIR}/.local/share/code-server/extensions"
LOG="${HOME_DIR}/code-server.log"
mkdir -p "${DATA_DIR}" "${EXT_DIR}"
chown -R "${USER}:${USER}" "${HOME_DIR}/.local/share"
ss -ltn | grep ":${PORT} " &>/dev/null && pkill -f "code-server.*:${PORT}"
echo "▶ 启动 ${USER} 的 code-server,端口 ${PORT}"
su – "$USER" -c "\\
nohup code-server \\
–auth password \\
–bind-addr 127.0.0.1:${PORT} \\
–user-data-dir \\"${DATA_DIR}\\" \\
–extensions-dir \\"${EXT_DIR}\\" \\
\\"${HOME_DIR}\\" \\
> \\"${LOG}\\" 2>&1 &\\
"
done
echo "✅ 所有 code-server 启动命令已发出"
EOF
chmod +x /usr/local/bin/start-all-code-servers.sh
/usr/local/bin/start-all-code-servers.sh
# 验证 code-server 是否在 8881~8890 端口监听
ss -ltnp | grep "888[1-9]\\|8890"
# 四、安装并启用 jupyter-server-proxy
pip install –no-cache-dir jupyter-server-proxy
jupyter server extension enable –sys-prefix jupyter_server_proxy
jupyter server extension list | grep proxy
# 五、配置“允许代理端口”:8881~8890
mkdir -p /opt/conda/etc/jupyter/jupyter_server_config.d
cat > /opt/conda/etc/jupyter/jupyter_server_config.d/proxy-allowed-ports.json << 'EOF'
{
"ServerProxy": {
"allowed_ports": [8881,8882,8883,8884,8885,8886,8887,8888,8889,8890]
}
}
EOF
# 六、启动 JupyterLab(绑定 8900,允许 root)
nohup jupyter lab –ip=0.0.0.0 –port=8900 –allow-root \\
> /var/log/jupyterlab.log 2>&1 &
# (或用 tmux: tmux new -s jlab; jupyter lab –ip=0.0.0.0 –port=8900 –allow-root; Ctrl+B D)
# 确认 JupyterLab 已在 8900 端口运行
ss -ltnp | grep 8900
# 七、在外部浏览器中使用示例
# (假设容器 8900映射到宿主机 23528)
# JupyterLab 主页:
# http://36.151.192.85:23528/lab?token=<token>
# test1 Code-Server:
# http://36.151.192.85:23528/proxy/8881/?folder=/home/test1
# test2 Code-Server:
# http://36.151.192.85:23528/proxy/8882/?folder=/home/test2
# …
# test10 Code-Server:
# http://36.151.192.85:23528/proxy/8890/?folder=/home/test10
# 八、(可选)关闭 code-server 密码验证
# 方案 1:修改 config.yaml
for U in test1 test2 test3 test4 test5 test6 test7 test8 test9 test10; do
CFG="/home/${U}/.config/code-server/config.yaml"
[ -f "$CFG" ] && sed -i 's/^auth: .*/auth: none/' "$CFG" && sed -i '/^password:/d' "$CFG"
# 重启对应的 code-server:
PORT=$(( 8880 + ${U##*t} )) # 简单算出 test1→8881, test2→8882, … (仅示例)
su – "$U" -c "pkill -f \\"code-server.*:${PORT}\\""
su – "$U" -c "nohup code-server –auth none –bind-addr 127.0.0.1:${PORT} /home/${U} > /home/${U}/code-server.log 2>&1 &"
done
# 方案 2:命令行覆盖
for idx in {1..10}; do
U="test${idx}"
PORT=$((8880 + idx))
su – "$U" -c "pkill -f \\"code-server.*:${PORT}\\""
su – "$U" -c "\\
nohup code-server \\
–auth none \\
–bind-addr 127.0.0.1:${PORT} \\
–user-data-dir \\"/home/${U}/.local/share/code-server\\" \\
–extensions-dir \\"/home/${U}/.local/share/code-server/extensions\\" \\
\\"/home/${U}\\" \\
> \\"/home/${U}/code-server.log\\" 2>&1 &\\
"
done
# 重新启动 JupyterLab(若它已暂停)
# pkill -f "jupyter lab.*8900"
# nohup jupyter lab –ip=0.0.0.0 –port=8900 –allow-root > /var/log/jupyterlab.log 2>&1 &
# 九、(可选)查看或停止进程
# 查看 code-server 是否占用端口
ss -ltnp | grep "888[1-9]\\|8890"
# 查看 JupyterLab 是否占用 8900
ss -ltnp | grep 8900
# 停止某个 code-server,例如 test3 监听 8883
pkill -f "code-server.*:8883"
# 停止 JupyterLab
pkill -f "jupyter-lab.*:8900"
关键思路和解决要点
多用户 Code-Server → 分别绑定不同端口(8881~8890)
- 确保每个用户的 code-server 都用 –bind-addr 127.0.0.1:888X 运行,避免互相冲突。
- 如果使用 config.yaml,也要把 bind-addr 改成对应端口;如果在命令行里直接覆盖 –bind-addr,就无需改 config.yaml。
JupyterLab 作为反向代理入口
- 安装并启用 jupyter-server-proxy 扩展,让 JupyterLab 能通过 /proxy/<port>/ 把请求转到 127.0.0.1:<port>。
- 在 JupyterLab 的配置目录下放一个 JSON 文件 proxy-allowed-ports.json,明确“允许代理的端口”列表。
JupyterLab 必须绑定一个与 code-server 不冲突的端口(如 8900),并加 –allow-root
-
原本的 8888、8889、8890 都被 code-server 占用了,JupyterLab 启动时会自动跳端口,但最后会因为“root”身份被拒绝退出。
-
改为:
jupyter lab –ip=0.0.0.0 –port=8900 –allow-root
-
确保外部映射把主机的高端口(比如 23528)指向容器的 8900。
长期运行建议
- 不要直接在终端前台启动 JupyterLab,否则关闭终端就会结束进程。可用 nohup & 或 tmux/screen 持久化运行。
- 同理,如果 Code-Server 也是以交互方式启动,只要终端关闭就停止;可考虑同样用 nohup 或 tmux 来让它持续后台跑。
可选:关闭 Code-Server 密码验证
- 在 config 文件里把 auth: password 改为 auth: none,或者在启动命令里加 –auth none,就能让用户无需密码,直接打开编辑器。
- 如若在公网环境,务必慎用“免密码”功能,否则任何人拿到代理 URL 都能直接进入用户的家目录。
十二、快速故障排查清单
“浏览器访问 /proxy/888X 报 502/404”
-
确认 JupyterLab 是否在后台运行:
ss -ltnp | grep 8900
-
确认 proxy-allowed-ports.json 是否存在、内容正确(端口集合是否包含 888X);
-
确认 code-server 的后端是否在 127.0.0.1:888X 监听:
ss -ltnp | grep 888X
“JupyterLab 启动报端口冲突”
- 原因:8888、8889、8890 都被 code-server 占用
- 解决:换一个空闲端口,如 –port=8900
“启动 jupyter lab 报 Running as root 错”
-
在命令末尾加 –allow-root
-
例:
jupyter lab –ip=0.0.0.0 –port=8900 –allow-root
“Code-Server 提示密码框,拿不到密码”
- 找到对应用户下的 ~/.config/code-server/config.yaml,看 password: <hash>;
- 或直接在 /usr/local/bin/start-all-code-servers.sh 里 把 –auth password 改为 –auth none,然后重启;
- 或手动在每个 config.yaml 里把 auth: password 改成 auth: none,然后重启 code-server。
“关掉终端后 JupyterLab 或 Code-Server 停了”
- 用 nohup … & 让它们自成后台;
- 或使用 tmux, screen 等会话管理工具;
- 更专业者可写 systemd service,让进程开机自启并自动重启。
总结
-
核心思路:
- 在容器里给每个用户单独启动 Code-Server,固定监听不同端口(8881~8890);
- 在同一个容器里启动 JupyterLab,并安装启用 jupyter-server-proxy;
- 在 JupyterLab 配置中“放行”8881~8890(proxy-allowed-ports.json);
- 让 JupyterLab 绑定到一个空闲端口(例如 8900),并加 –allow-root 后台运行;
- 外部浏览器通过 /proxy/888X/ 路径,就被反代到 127.0.0.1:888X(对应用户的 Code-Server),实现多用户隔离的 VS Code Web IDE。
-
关键命令示例:
- useradd / chpasswd → 创建用户
- curl … | sh → 安装 code-server
- ss -ltnp | grep 8881 → 检查 code-server 是否监听
- pip install jupyter-server-proxy & jupyter server extension enable –sys-prefix jupyter_server_proxy → 安装启用代理扩展
- cat > …/proxy-allowed-ports.json → 放行 8881~8890
- jupyter lab –ip=0.0.0.0 –port=8900 –allow-root & (或 nohup 、tmux)→ 启动 JupyterLab
- 浏览器访问 http://<主机>:<映射端口>/proxy/888X/ → 进入对应用户的 VS Code Web IDE
只要照着这份详细备份,从用户创建、code-server 启动、JupyterLab 安装到代理配置,每一步都做一遍,就可以在同一个容器内为多位用户提供独立的 VS Code Web IDE,各自访问 /proxy/8881~8890/ 即可。今后遇到类似场景,便可参照此流程快速部署。
评论前必须登录!
注册