# Linux 服务器部署 code-server（网页版 VSCode）计划

> 当前状态：待实施。端口、版本和主机资源数据为 2026-09-30 的规划/核查结果；开始安装前必须重新检查，并在 [计划总表](README.md) 更新状态。

## 一、目标与选型理由

让 Windows（或其他设备）**用浏览器直接访问服务器上的 VSCode 编辑环境**，作为 VSCode 官方远程隧道的替代方案。

### 为什么不用 VSCode 官方隧道

官方隧道（`code tunnel` + vscode.dev）在本网络环境下走不通，实测证据：

| 端点 | 实测结果 |
| --- | --- |
| `tunnels.api.visualstudio.com` | **DNS 无应答**（系统 DNS、223.5.5.5、119.29.29.29 全部无结果） |
| `github.com`（对照组） | 正常解析 `20.205.243.166` |
| `vscode.dev:443` | 通，握手 0.15s |
| `main.vscode-cdn.net:443` | 通，握手 0.05s |
| `login.microsoftonline.com:443` | 通 |

`code tunnel` 注册时必须先连 `*.tunnels.api.visualstudio.com`，该域名在国内被 DNS 层面屏蔽，**不是配置能绕过的**。而且隧道要经微软中继（杭州→微软→杭州），估算 150ms+，**比现有 11ms 直连更慢**。

### code-server 方案对比

| 对比项 | 官方隧道 | code-server |
| --- | --- | --- |
| 中继路径 | 经微软中继，150ms+ | **直连，11ms（复用现有 Tailscale）** |
| 第三方依赖 | 微软账户 + 隧道域名（当前被屏蔽） | 无 |
| 静态资源 | 依赖 `*.vscode-cdn.net` | **全部本地提供，不依赖任何 CDN** |
| 公网依赖 | 需要 | 不需要（走 Tailscale，不依赖端口映射） |
| 安装体积 | 官方客户端 | 211.9 MB（解压后约 500MB） |
| 断网风险 | 微软服务变动即失效 | 完全自控 |

---

## 二、前置条件（2026-09-30 已核实）

| 项目 | 值 | 说明 |
| --- | --- | --- |
| 服务器 | `zrh-dracarys` / `100.99.232.7` / Ubuntu 24.04.5 | |
| code-server 版本 | `4.139.1` | GitHub API 确认的最新正式版 |
| 安装包体积 | 211.9 MB | 官方未提供该资产的 `.sha256sum` |
| 服务器到 GitHub 下载速度 | **2.36 MB/s** | 预计下载约 90 秒 |
| 依赖共享库 | `libstdc++6` / `libgcc_s1` / `libatomic1` / `libnss3` / `libatk-1.0` / `libgbm` **全部已就绪** | **无需 sudo 装任何依赖** |
| 空闲端口 | `8444`（`8443` 已被 derper 占用） | |
| 剩余磁盘 | 365 G | 占用约 0.5% |
| 权限 | **无免密 sudo** | 全程用用户级安装 + 用户级 systemd |
| `Linger` | `no` | 详见第八节，重启后不会自启 |

---

## 三、部署步骤

### 步骤 1：下载安装包

```bash
ssh zrh-server
cd ~
wget https://github.com/coder/code-server/releases/download/v4.139.1/code-server-4.139.1-linux-amd64.tar.gz
ls -lh code-server-4.139.1-linux-amd64.tar.gz
```

期望看到约 `212M`。

### 步骤 2：解压到用户目录（免 sudo）

```bash
mkdir -p ~/.local/lib ~/.local/bin
tar -xzf ~/code-server-4.139.1-linux-amd64.tar.gz -C ~/.local/lib/ --strip-components=1
ln -sf ~/.local/lib/bin/code-server ~/.local/bin/code-server
~/.local/bin/code-server --version
```

期望输出 `4.139.1 <commit>`。

下载完可以清理安装包：`rm ~/code-server-4.139.1-linux-amd64.tar.gz`（省 212MB）。

### 步骤 3：生成配置

```bash
mkdir -p ~/.config/code-server
cat > ~/.config/code-server/config.yaml <<'EOF'
bind-addr: 100.99.232.7:8444
auth: password
password: 这里换成你自己的强密码
cert: false
EOF
chmod 600 ~/.config/code-server/config.yaml
```

三个配置项的含义：

| 配置项 | 本文档取值 | 说明 |
| --- | --- | --- |
| `bind-addr` | `100.99.232.7:8444` | **只监听 Tailscale 网卡**，tailnet 内的设备能访问，家庭局域网访问不到。这是安全面最小的选择 |
| `auth` | `password` | 密码登录。**不要改成 `none`** |
| `password` | 自定义，**至少 8 位** | 少于 8 位 code-server 会启动失败 |
| `cert` | `false` | 不启用 HTTPS。Tailscale 本身用 WireGuard 加密，tailnet 内部用明文 HTTP 是安全的 |

绑定地址的三个选项，按安全面从小到大：

| 写法 | 谁能访问 | 建议 |
| --- | --- | --- |
| `100.99.232.7:8444`（Tailscale IP） | 仅 tailnet 内设备 | **推荐** |
| `192.168.31.145:8444`（内网 IP） | 仅家庭局域网 | 需要在家用浏览器时选 |
| `0.0.0.0:8444` | 上述两者 | 不建议，暴露面最大 |

### 步骤 4：注册为用户级 systemd 服务（免 sudo）

```bash
mkdir -p ~/.config/systemd/user
cat > ~/.config/systemd/user/code-server.service <<'EOF'
[Unit]
Description=code-server (web VSCode)
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=%h/.local/bin/code-server --config %h/.config/code-server/config.yaml
Restart=always
RestartSec=3
Environment=HOME=%h

[Install]
WantedBy=default.target
EOF

systemctl --user daemon-reload
systemctl --user enable --now code-server
systemctl --user status code-server --no-pager
```

期望看到 `Active: active (running)`。

### 步骤 5：服务器本机验证

服务器没装 `curl`，用 `wget` 或 python3 探测：

```bash
wget -q -S -O /dev/null --spider http://100.99.232.7:8444 2>&1 | head -4
```

期望输出 `HTTP/1.1 302 Found` 和 `Location: /login`。

确认端口监听：

```bash
ss -tln | grep 8444
```

期望 `LISTEN 0 4096 100.99.232.7:8444`。

### 步骤 6：Windows 侧验证

```powershell
Test-NetConnection 100.99.232.7 -Port 8444
```

期望 `TcpTestSucceeded : True`。

### 步骤 7：浏览器访问

在 Windows 浏览器地址栏输入：

```text
http://100.99.232.7:8444
```

会自动跳转到登录页，输入步骤 3 设的密码即可。

---

## 四、扩展安装

code-server 用**独立的扩展目录** `~/.local/share/code-server/extensions`，不会自动继承 `~/.vscode-server` 里的 20 个扩展，需要单独装。

### 推荐装的扩展

服务器现有扩展中，对网页端有实际价值的是这几个：

| 扩展 ID | 用途 | 网页端是否有意义 |
| --- | --- | --- |
| `llvm-vs-code-extensions.vscode-clangd` | C/C++ 语言服务 | **有**，服务器上自带 clangd，不依赖 armcc |
| `ms-ceintl.vscode-language-pack-zh-hans` | 中文界面 | **有** |
| `eamodio.gitlens` | Git 历史可视化 | **有** |
| `hybridtalentcomputing.cline-chinese` | AI 插件中文包 | 视需要 |
| `cl.eide` | 嵌入式项目管理和烧录 | **无**，服务器上没有接开发板，烧录功能用不了 |
| `mcu-debug.debug-tracker-vscode` | MCU 调试跟踪 | **无**，同上 |

用命令行装：

```bash
~/.local/bin/code-server --extensions-dir ~/.local/share/code-server/extensions \
  --install-extension llvm-vs-code-extensions.vscode-clangd
```

也可以在网页版里点扩展面板直接装。

### 迁移已有扩展目录（有风险，谨慎）

理论上可以把现有扩展目录复制过去：

```bash
cp -r ~/.vscode-server/extensions/* ~/.local/share/code-server/extensions/
```

**但这是非官方做法**，`.vscode-server` 与 code-server 的扩展宿主版本可能不同，复制后可能出现扩展不加载或版本不匹配。**建议只复制上面那几个确认需要的，其余在网页端按需安装。**

---

## 五、设置迁移注意事项

Windows 端 `settings.json` 里的配置**不能直接照搬**，以下几项在服务器上要改：

| Windows 配置 | 服务器上的处理 |
| --- | --- |
| `clangd.arguments` 里的 `--query-driver=D:/Keil_v5/ARM/ARMCC/bin/armcc.exe` | **必须删掉**。这是 Windows 路径，Linux 上不存在，会导致 clangd 报错 |
| `"files.encoding": "gbk"` | 服务器上按需改，建议 `utf-8` |
| `KeilAssistant.MDK.Uv4Path`（`D:\app\Keil_v5\...`） | **必须删掉**，Windows 专用 |
| `remote.SSH.remotePlatform` | 网页端不需要 |
| `clangd.path`（指向 Windows 的 clangd.exe） | **必须删掉**，用扩展自带的 |

建议在网页端新建一份干净的 `settings.json`，只放真正需要跨平台的配置。

---

## 六、验证清单

| 检查项 | 命令 | 期望结果 |
| --- | --- | --- |
| 服务运行 | `systemctl --user is-active code-server` | `active` |
| 端口监听 | `ss -tln \| grep 8444` | `100.99.232.7:8444` |
| 本机响应 | `wget -q -S -O /dev/null --spider http://100.99.232.7:8444 2>&1 \| head -2` | `HTTP/1.1 302 Found` |
| 服务日志 | `journalctl --user -u code-server -n 20 --no-pager` | 无报错 |
| Windows 可达 | `Test-NetConnection 100.99.232.7 -Port 8444` | `True` |
| 浏览器 | 打开 `http://100.99.232.7:8444` | 跳转登录页 |
| 登录 | 输入密码 | 进入编辑器，能打开文件 |

---

## 七、日常运维

```bash
# 启动 / 停止 / 重启
systemctl --user start   code-server
systemctl --user stop    code-server
systemctl --user restart code-server

# 查看状态和日志
systemctl --user status code-server --no-pager
journalctl --user -u code-server -f            # 实时跟随日志

# 改端口：编辑 config.yaml 的 bind-addr 后重启
vi ~/.config/code-server/config.yaml
systemctl --user restart code-server

# 改密码：编辑 config.yaml 的 password 后重启
vi ~/.config/code-server/config.yaml
systemctl --user restart code-server

# 开机自启：已由 enable 设置，但受 linger 限制（见下）
systemctl --user is-enabled code-server

# 卸载
systemctl --user disable --now code-server
rm ~/.config/systemd/user/code-server.service
systemctl --user daemon-reload
rm -rf ~/.config/code-server ~/.local/share/code-server ~/.local/lib ~/.local/bin/code-server
```

### 升级到新版本

```bash
systemctl --user stop code-server
cd /tmp
wget https://github.com/coder/code-server/releases/download/<新版本>/code-server-<新版本>-linux-amd64.tar.gz
tar -xzf code-server-<新版本>-linux-amd64.tar.gz -C ~/.local/lib/ --strip-components=1
systemctl --user start code-server
~/.local/bin/code-server --version
```

---

## 八、开机自启的 linger 限制

和 derper 一样，`loginctl show-user zrh` 显示 `Linger=no`，含义是：**服务器重启后、zrh 没有 SSH 登录时，用户级服务不会自动启动。**

- 平时不影响：只要 zrh 有登录会话，服务就在跑
- 需要解决的话，两个办法：
  1. `loginctl enable-linger zrh` —— **需要管理员权限**（sudo）
  2. 改成系统级 systemd service —— 同样需要 sudo

`zrh` 没有免密 sudo，所以这一项目前无解，和 derper 的情况相同。

---

## 九、安全说明

1. **tailnet 内任何设备都能访问这个端口。** 包括 `dracarys`（`100.96.158.37`）以及以后新加入的设备。所以密码认证必须开着，且密码要够强。
2. **想更严格**，可以在 Tailscale 管理后台用 ACL 限制：只允许特定设备访问服务器的 8444 端口。
3. **不要把 `bind-addr` 改成 `0.0.0.0`** 除非你确实需要局域网访问 —— 那会让家庭网络内任何设备都能扫到这个端口。
4. **用 HTTP 而不是 HTTPS 是安全的**，因为 Tailscale 的 WireGuard 已经在底层加密了。密码通过 tailnet 传输不会明文暴露。
5. **改完密码要重启服务才生效。**

---

## 十、回滚

| 步骤 | 操作 |
| --- | --- |
| 1 | `systemctl --user disable --now code-server` |
| 2 | `rm ~/.config/systemd/user/code-server.service` |
| 3 | `systemctl --user daemon-reload` |
| 4 | `rm -rf ~/.config/code-server ~/.local/share/code-server` |
| 5 | `rm -rf ~/.local/lib ~/.local/bin/code-server`（仅此步会删掉 `~/.local/lib` 下的其他内容，若该目录原本有别的文件请勿执行） |
| 6 | 端口 8444 自动释放 |

不影响 Remote-SSH、不影响 derper、不影响 Tailscale。

---

## 十一、排查

| 现象 | 可能原因 | 处理 |
| --- | --- | --- |
| 服务启动失败，日志提示 `password` 太短 | 密码少于 8 位 | 改长密码后重启 |
| 服务启动失败，提示 `EADDRINUSE` | 8444 被占用 | `ss -tln \| grep 8444` 查占用者，或改端口 |
| Windows 侧 `TcpTestSucceeded: False` | 服务没起 / 绑错了地址 | 服务器上跑 `ss -tln \| grep 8444`，确认绑定的是 Tailscale IP |
| 本机 `wget` 通、Windows 不通 | Windows 侧 Tailscale 断了 | `tailscale status` 检查 |
| 浏览器一直转圈或空白 | 静态资源加载失败 | code-server 资源全部本地提供，若出现此问题看 `journalctl --user -u code-server` |
| 打开大目录很慢 | 首次索引 | 正常，等待即可 |
| 扩展装了不生效 | 版本不匹配 | 查网页端扩展面板的报错 |
| 忘记密码 | — | `vi ~/.config/code-server/config.yaml` 改掉，重启服务 |
| 扩展目录复制后扩展全失效 | 从 `.vscode-server` 复制导致不兼容 | 清空 `~/.local/share/code-server/extensions` 后在网页端重装 |

---

## 十二、与现有方案的关系

| 方案 | 路径 | 延迟 | 定位 |
| --- | --- | --- | --- |
| Remote-SSH（VSCode 插件） | Tailscale 直连 | **11ms** | **主力**，功能完整、体验最好 |
| code-server（本方案） | Tailscale 直连 | 11ms | **网页备用**，手机/平板/无 VSCode 客户端时用 |
| 官方 VSCode 隧道 | 微软中继 | — | **当前不可用**，隧道域名被 DNS 屏蔽 |
| 自建杭州 DERP（方案 A） | Tailscale 直连 | — | 双 NAT 兜底，直连失效时启用 |
