Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ One shared proxy core. The active path configures an existing CStoneCloud or oth

### CStoneCloud / 已有 Debian/Ubuntu VPS

新机安装 Debian/Ubuntu 后,优先在 CStoneCloud 面板的「SSH 密钥」页面绑定本机公钥,然后复制旧 cstone 的非密钥配置、生成全新凭据并部署:
新机安装 Debian/Ubuntu 后,优先在 CStoneCloud 面板的「SSH 密钥」页面绑定本机公钥,然后复制当前 CStoneCloud profile 的非密钥配置、生成全新凭据并部署:

```bash
./deploy-vps.sh \
--profile cstone-next \
--host <VPS_PUBLIC_IP> \
--ssh-key "$HOME/.ssh/cstone_ed25519" \
--copy-config-from cstone
--copy-config-from cstonecloud-cuii-a
```

绑定后先用一个新终端验证 root 公钥登录。若面板没有注入公钥,再加 `--install-key`:它会调用系统 `ssh-copy-id` 并交互式提示输入 root 密码;密码不会写入项目、参数或日志。该私钥旁需要存在同名 `.pub` 公钥文件。
Expand All @@ -34,7 +34,7 @@ One shared proxy core. The active path configures an existing CStoneCloud or oth
--ssh-key "$HOME/.ssh/cstone_ed25519" --check-only
```

`VPS_PROFILE` / `--profile` 必须为每台 VPS 使用唯一名称,例如 `cstone`、`cstone-next`、`los-angeles-02`。
`VPS_PROFILE` / `--profile` 必须为每台 VPS 使用唯一名称,例如 `cstonecloud-cuii-a`、`cstone-next`、`los-angeles-02`。
不要裸跑 `./deploy-vps.sh`,这样可以避免新服务器误用已有 profile。

VPS adapter 会执行以下安全步骤:
Expand Down Expand Up @@ -191,7 +191,7 @@ Cloudflare 权限不足时,部署会在修改服务器前停止,不会留下

```bash
# Active path: configure an existing CStoneCloud/Debian/Ubuntu VPS
./deploy-vps.sh --profile cstone-next --host <VPS_PUBLIC_IP> --ssh-key "$HOME/.ssh/cstone_ed25519" --copy-config-from cstone
./deploy-vps.sh --profile cstone-next --host <VPS_PUBLIC_IP> --ssh-key "$HOME/.ssh/cstone_ed25519" --copy-config-from cstonecloud-cuii-a

# Dormant path: provision a Google Cloud node
./deploy-gcp.sh
Expand Down
2 changes: 1 addition & 1 deletion core/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -123,5 +123,5 @@ run_deploy() {
if [ "${CDN_ENABLE:-false}" = "true" ]; then
echo " CDN : $CDN_HOSTNAME"
fi
echo " 配置文件 : $CLIENTS_DIR/${PROFILE_NAME}-*.yaml"
echo " 配置文件 : $CLIENTS_DIR/${CLIENT_FILE_PREFIX:-$PROFILE_NAME}-*.yaml"
}
2 changes: 1 addition & 1 deletion deploy-vps.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ usage() {
示例:
./deploy-vps.sh --profile cstone-next --host 203.0.113.10 \
--ssh-key "$HOME/.ssh/cstone_ed25519" \
--copy-config-from cstone
--copy-config-from cstonecloud-cuii-a
USAGE
}

Expand Down
6 changes: 3 additions & 3 deletions docs/provider-onboarding.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ Use one profile per server. A profile name is a local namespace for the server's

1. Install Debian 12/13 64-bit or Ubuntu 24.04 LTS.
2. Prefer binding a saved public key in the provider panel, then verify root key login from a new terminal. If that fails, use the provider's root password interactively with `--install-key`. Keep the private key on the local machine only.
3. Run the generic VPS entry point with an explicit, unique profile name. For a CStoneCloud replacement that should inherit cstone's non-secret settings:
3. Run the generic VPS entry point with an explicit, unique profile name. For a CStoneCloud replacement that should inherit the current profile's non-secret settings:

```bash
./deploy-vps.sh --profile cstone-next --host <VPS_PUBLIC_IP> \
--ssh-key "$HOME/.ssh/cstone_ed25519" \
--copy-config-from cstone
--copy-config-from cstonecloud-cuii-a
```

Add `--install-key` only if the provider did not install the public key. Use a different profile for every server, for example `cstone`, `cstone-next`, or `new-york-01`. Do not run `./deploy-vps.sh` without a profile.
Add `--install-key` only if the provider did not install the public key. Use a different profile for every server, for example `cstonecloud-cuii-a`, `cstone-next`, or `new-york-01`. Do not run `./deploy-vps.sh` without a profile. When copying a profile, the new profile resets `CLIENT_FILE_PREFIX` to its own name so both generations of client YAML can coexist during cutover.

The first run creates `profiles/<profile>/deploy.conf` and `.secrets.env`, secures the host, creates the `mt` sudo user, installs the shared protocols, and writes:

Expand Down
4 changes: 2 additions & 2 deletions docs/repository-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ docs/ 架构、排障和运维说明
```bash
./deploy-vps.sh --profile cstone-next --host <VPS_PUBLIC_IP> \
--ssh-key "$HOME/.ssh/cstone_ed25519" \
--copy-config-from cstone
--copy-config-from cstonecloud-cuii-a
```

优先在商家面板绑定 SSH 公钥;只有面板注入失败时才加 `--install-key`。VPS 适配器负责可选的交互式公钥安装、远端 readiness、创建 `mt` 管理员、UFW 和文件上传。每台 VPS 必须使用唯一 profile,避免误读另一台服务器的状态。迁移时只复制旧 profile 的非密钥 `deploy.conf`,不会复制凭据或客户端 YAML。
优先在商家面板绑定 SSH 公钥;只有面板注入失败时才加 `--install-key`。VPS 适配器负责可选的交互式公钥安装、远端 readiness、创建 `mt` 管理员、UFW 和文件上传。每台 VPS 必须使用唯一 profile,避免误读另一台服务器的状态。迁移时只复制旧 profile 的非密钥 `deploy.conf`,不会复制凭据或客户端 YAML;新 profile 会将 `CLIENT_FILE_PREFIX` 重置为自己的名称,避免覆盖旧节点配置

### GCP(当前未使用)

Expand Down
8 changes: 4 additions & 4 deletions docs/vps-migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,24 +34,24 @@ Do not test reinstall or key-removal behavior on the active node merely to valid

Prepare a local keypair once. Keep the private key local and ensure the matching `.pub` file exists beside it.

For a replacement server with the panel-bound key already verified, use cstone's non-secret settings:
For a replacement server with the panel-bound key already verified, use the current `cstonecloud-cuii-a` profile's non-secret settings:

```bash
./deploy-vps.sh \
--profile cstone-next \
--host <NEW_PUBLIC_IP> \
--ssh-key "$HOME/.ssh/cstone_ed25519" \
--copy-config-from cstone
--copy-config-from cstonecloud-cuii-a
```

This sequence:

1. Checks Debian/Ubuntu, x86_64/aarch64, root or passwordless sudo, and systemd before creating profile state.
2. Copies only `profiles/cstone/deploy.conf`. It never copies `.secrets.env`, SSH keys, or generated client YAML.
2. Copies only `profiles/cstonecloud-cuii-a/deploy.conf`, resetting `CLIENT_FILE_PREFIX` to `cstone-next`. It never copies `.secrets.env`, SSH keys, or generated client YAML.
3. Generates independent credentials under `profiles/cstone-next/`.
4. Creates and verifies the `mt` sudo user before disabling root/password SSH.
5. Installs the server stack and fails the deployment if any required systemd unit is inactive.
6. Generates `clash-configs/cstone-next-*.yaml` without changing cstone's files.
6. Generates `clash-configs/cstone-next-*.yaml` without changing the current `cstonecloud-*.yaml` files.

If panel key binding is unavailable or unsuccessful, add `--install-key` to the deployment command. It uses `ssh-copy-id`; the root password is entered interactively and is never stored by this project. To validate an already keyed host without changing it:

Expand Down
4 changes: 3 additions & 1 deletion providers/vps.sh
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,9 @@ provider_configure() {
[ -f "$source_conf" ] \
|| die "来源 profile 不存在 deploy.conf:profiles/$VPS_CONFIG_FROM_PROFILE/"
cp "$source_conf" "$CONF_FILE"
ok "已从 $VPS_CONFIG_FROM_PROFILE 复制非密钥部署配置;新 profile 会生成独立凭据"
sed -i.bak -e "s|^CLIENT_FILE_PREFIX=.*|CLIENT_FILE_PREFIX=$PROFILE_NAME|" "$CONF_FILE"
rm -f "$CONF_FILE.bak"
ok "已从 $VPS_CONFIG_FROM_PROFILE 复制非密钥部署配置;新 profile 会生成独立凭据和客户端文件"
else
cp "$CONFIG_TEMPLATE" "$CONF_FILE"
sed -i.bak -e 's|^PROJECT_ID=.*|PROJECT_ID=vps|' "$CONF_FILE"
Expand Down
16 changes: 11 additions & 5 deletions tests/test_deploy_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ def test_vps_profile_is_passed_to_secret_generation_subprocess(self):
provider_configure() {{
mkdir -p \"$STATE_DIR\"
cp \"$PROJECT_DIR/config/deploy.conf.example\" \"$CONF_FILE\"
printf 'CLIENT_FILE_PREFIX=frantech-client\\n' >> \"$CONF_FILE\"
}}
provider_provision() {{ setkv STATIC_IP 203.0.113.10; }}
provider_install() {{ printf 'REALITY_PUBLIC_KEY=test-public-key\\n'; }}
Expand All @@ -177,9 +178,9 @@ def test_vps_profile_is_passed_to_secret_generation_subprocess(self):
printf '%s\\n' \"$output\"
test -f \"$STATE_DIR/.secrets.env\"
test ! -e \"$PROJECT_DIR/profiles/gcloud/.secrets.env\"
test -f \"$PROJECT_DIR/clash-configs/frantech-mac.yaml\"
test -f \"$PROJECT_DIR/clash-configs/frantech-iphone.yaml\"
grep -F '配置文件 : {root}/clash-configs/frantech-*.yaml' <<<\"$output\" >/dev/null
test -f \"$PROJECT_DIR/clash-configs/frantech-client-mac.yaml\"
test -f \"$PROJECT_DIR/clash-configs/frantech-client-iphone.yaml\"
grep -F '配置文件 : {root}/clash-configs/frantech-client-*.yaml' <<<\"$output\" >/dev/null
"""
)
result = subprocess.run(
Expand All @@ -190,13 +191,14 @@ def test_vps_profile_is_passed_to_secret_generation_subprocess(self):
)
self.assertEqual(result.returncode, 0, result.stderr + result.stdout)

def test_vps_provider_copies_only_non_secret_config_for_new_profile(self):
def test_vps_provider_copies_non_secret_config_with_isolated_client_prefix(self):
with tempfile.TemporaryDirectory() as tmp:
root = pathlib.Path(tmp)
source_state = root / "profiles" / "cstone"
source_state.mkdir(parents=True)
(source_state / "deploy.conf").write_text(
"PROJECT_ID=vps\nDEVICES=mac\nREALITY_PORT=443\n"
"CLIENT_FILE_PREFIX=cstonecloud\n"
)
(source_state / ".secrets.env").write_text("DO_NOT_COPY=secret\n")
command = textwrap.dedent(
Expand All @@ -213,7 +215,11 @@ def test_vps_provider_copies_only_non_secret_config_for_new_profile(self):
. "$PROJECT_DIR/core/common.sh"
. "$PROJECT_DIR/providers/vps.sh"
provider_configure >/dev/null
cmp "$PROJECT_DIR/profiles/cstone/deploy.conf" "$CONF_FILE"
grep -Fx 'PROJECT_ID=vps' "$CONF_FILE" >/dev/null
grep -Fx 'DEVICES=mac' "$CONF_FILE" >/dev/null
grep -Fx 'REALITY_PORT=443' "$CONF_FILE" >/dev/null
grep -Fx 'CLIENT_FILE_PREFIX=cstone-next' "$CONF_FILE" >/dev/null
grep -Fx 'CLIENT_FILE_PREFIX=cstonecloud' "$PROJECT_DIR/profiles/cstone/deploy.conf" >/dev/null
test ! -e "$STATE_DIR/.secrets.env"
"""
)
Expand Down