云计算百科
云计算领域专业知识百科平台

Jupyter notebook 容器内服务器多用户管理方法

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 启动在容器的 8900 端口;
  • jupyter-server-proxy 拓展加载完成,已经准备对外放行 8881~8890;
  • 确认 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/ 即可。今后遇到类似场景,便可参照此流程快速部署。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » Jupyter notebook 容器内服务器多用户管理方法
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!