From 01da358211a866369dec89643cf21016e815f5a5 Mon Sep 17 00:00:00 2001 From: Martin <60476606+mtmtian@users.noreply.github.com> Date: Thu, 20 Aug 2026 04:42:42 +0800 Subject: [PATCH] isolate client files when copying profiles --- README.md | 8 ++++---- core/deploy.sh | 2 +- deploy-vps.sh | 2 +- docs/provider-onboarding.md | 6 +++--- docs/repository-guide.md | 4 ++-- docs/vps-migration.md | 8 ++++---- providers/vps.sh | 4 +++- tests/test_deploy_output.py | 16 +++++++++++----- 8 files changed, 29 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 466ee3c..f0b032a 100644 --- a/README.md +++ b/README.md @@ -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 \ --ssh-key "$HOME/.ssh/cstone_ed25519" \ - --copy-config-from cstone + --copy-config-from cstonecloud-cuii-a ``` 绑定后先用一个新终端验证 root 公钥登录。若面板没有注入公钥,再加 `--install-key`:它会调用系统 `ssh-copy-id` 并交互式提示输入 root 密码;密码不会写入项目、参数或日志。该私钥旁需要存在同名 `.pub` 公钥文件。 @@ -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 会执行以下安全步骤: @@ -191,7 +191,7 @@ Cloudflare 权限不足时,部署会在修改服务器前停止,不会留下 ```bash # Active path: configure an existing CStoneCloud/Debian/Ubuntu VPS -./deploy-vps.sh --profile cstone-next --host --ssh-key "$HOME/.ssh/cstone_ed25519" --copy-config-from cstone +./deploy-vps.sh --profile cstone-next --host --ssh-key "$HOME/.ssh/cstone_ed25519" --copy-config-from cstonecloud-cuii-a # Dormant path: provision a Google Cloud node ./deploy-gcp.sh diff --git a/core/deploy.sh b/core/deploy.sh index 00af429..ab4a281 100755 --- a/core/deploy.sh +++ b/core/deploy.sh @@ -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" } diff --git a/deploy-vps.sh b/deploy-vps.sh index 18b708e..52223ed 100755 --- a/deploy-vps.sh +++ b/deploy-vps.sh @@ -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 } diff --git a/docs/provider-onboarding.md b/docs/provider-onboarding.md index d72b887..207d9cf 100644 --- a/docs/provider-onboarding.md +++ b/docs/provider-onboarding.md @@ -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 \ --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//deploy.conf` and `.secrets.env`, secures the host, creates the `mt` sudo user, installs the shared protocols, and writes: diff --git a/docs/repository-guide.md b/docs/repository-guide.md index 260c3d3..a4e5c38 100644 --- a/docs/repository-guide.md +++ b/docs/repository-guide.md @@ -43,10 +43,10 @@ docs/ 架构、排障和运维说明 ```bash ./deploy-vps.sh --profile cstone-next --host \ --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(当前未使用) diff --git a/docs/vps-migration.md b/docs/vps-migration.md index 4fcc838..b6b9bd7 100644 --- a/docs/vps-migration.md +++ b/docs/vps-migration.md @@ -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 \ --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: diff --git a/providers/vps.sh b/providers/vps.sh index 9168b5e..98e9bef 100755 --- a/providers/vps.sh +++ b/providers/vps.sh @@ -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" diff --git a/tests/test_deploy_output.py b/tests/test_deploy_output.py index 857dc6b..e27e322 100644 --- a/tests/test_deploy_output.py +++ b/tests/test_deploy_output.py @@ -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'; }} @@ -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( @@ -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( @@ -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" """ )