---
name: xserver
description: >
  Deploy and manage websites on XServer / エックスサーバー using the XServer API and SSH.
  Use for requests like 「エックスサーバーにデプロイ」「XServer APIで設定」「WordPressを入れて」
  「サイト公開」「LP作って公開」「サブドメイン追加」「メールアドレス作成」
  「DNS変更」「WordPress削除」「ドメインとSSLを設定」「DNS/メール/Cron/SSH/FTPを管理」.
  Confirm before secrets, public destinations, SSH changes, deletion, reset, or rsync --delete.
metadata:
  author: xserver-inc
  version: "1.0.0"
tags:
  - deployment
  - hosting
  - xserver
platforms:
  - cursor
  - claude-code
  - gemini-cli
  - cline
  - codex
---

# XServer Deploy & Manage

エックスサーバーへのデプロイとサーバー管理を自動化するスキル。
REST API によるサーバー設定と SSH によるファイルデプロイの両方をサポートする。

- 対象サービス: エックスサーバー（スタンダード / プレミアム / ビジネス）
- API リファレンス: https://developer.xserver.ne.jp/api/server/
- OpenAPI 仕様（JSON）: https://developer.xserver.ne.jp/api/server/openapi.json

## Agent Rules (MUST READ FIRST)

- API キーをチャット本文に貼るよう案内してはならない
- API キーを `echo` / `printf` 等でコマンドに含めてはならない
- API キーはファイルに直接書き込んではならない（`echo "key" > file` 禁止）
- API キーは環境変数 `$XSERVER_API_KEY` 経由でのみ受け取る
- 環境変数が未設定なら作業を止めて設定方法を案内し待機する

## Prerequisites

- エックスサーバーの契約
- XServer アカウントで API キーを発行済み（https://www.xserver.ne.jp/manual/man_tool_api.php）
- SSH 有効化・公開鍵の登録はすべて API 経由で実施（手動でサーバーパネル操作は不要）
- macOS: `rsync`（標準搭載）、`jq`（`brew install jq`）
- Windows: `rsync`（`scoop install rsync` または WSL）、`jq`（`scoop install jq`）、`CredentialManager` モジュール
- Linux: `curl`、`jq`、`rsync`、`ssh`、および `secret-tool`（推奨）または `pass`

---

## Step 1: Setup

### 1-1. API キーの取得

ユーザーに以下を確認:

```
API キーはチャット本文には貼らず、可能ならターミナルの環境変数として設定してください。
エックスサーバーの API キーを用意してください。
XServer アカウントにログイン（https://secure.xserver.ne.jp/xapanel/login/xserver/）し、サイドメニューの「APIキー管理」から発行できます。
参考: https://www.xserver.ne.jp/manual/man_tool_api.php

例（bash / zsh）:
export XSERVER_API_KEY="<APIキー>"
```

共有端末ではシェル履歴やログに残らないよう注意する。
ユーザーが API キーをチャットに貼った場合、その値を繰り返さずに処理を続行し、完了後にローテーションを案内する。

**【エージェント厳守】キーを平文でコマンドに含めることは絶対禁止。**
`printf %s 'xs_abc...' > file` や `echo 'xs_abc...'` のような形でキーをリテラルとしてシェルコマンドに渡してはならない。シェル履歴・ログ・会話履歴にキーが残る。TTY がない場合は後述のエージェント向け代替手順に従う。

### 1-2. Preflight チェック

```bash
for cmd in curl jq ssh rsync; do command -v "$cmd" >/dev/null || echo "missing:$cmd"; done
command -v security >/dev/null || true
command -v secret-tool >/dev/null || true
```

```powershell
"curl","jq","ssh","rsync" | ForEach-Object { if (-not (Get-Command $_ -ErrorAction SilentlyContinue)) { Write-Output "missing:$_" } }; if (-not (Get-Module -ListAvailable -Name CredentialManager)) { Install-Module -Name CredentialManager -Scope CurrentUser -Force }
```

不足コマンドがあれば、先にインストールしてから次へ進む。

### 1-3. API キーの検証と servername 取得

```bash
SERVERNAME=$(curl -s -X GET "https://api.xserver.ne.jp/v1/me" \
  -H "Authorization: Bearer $XSERVER_API_KEY" | jq -r '.servername')
# 例: xs123456.xsrv.jp
```

`SERVERNAME` を以降の全 API リクエストで使用する。

### 1-4. API キーの安全な保存

**最低限の要件: 環境変数 `XSERVER_API_KEY` でエージェントに渡す。** 平文ファイル（`.env` 等）への直接記述や、コマンド引数へのリテラル埋め込みは禁止。具体的な保存・管理方法は環境とポリシーに応じてユーザーが選択する。

#### 環境の自動判定

```bash
case "$(uname -s)" in
  Darwin)                echo "→ macOS: Keychain（security コマンド）を推奨" ;;
  Linux)                 echo "→ Linux/VPS: secret-tool または export を推奨" ;;
  MINGW*|MSYS*|CYGWIN*)  echo "→ Windows (Git Bash): PowerShell の DPAPI を推奨" ;;
  *)                     echo "→ 不明: export XSERVER_API_KEY で設定してください" ;;
esac
```

#### 推奨方法と参考コマンド

| 環境 | 推奨方法 |
|---|---|
| macOS | Keychain（`security add-generic-password` / `find-generic-password`） |
| Windows | Credential Manager / DPAPI（`Export-Clixml` / `Import-Clixml`） |
| Linux（GUI あり） | libsecret（`secret-tool`）または `pass` |
| Linux / VPS / コンテナ | セッション限定の環境変数（エージェント起動前に `read -sp` → `export`） |
| CI/CD | プラットフォームのシークレット管理（GitHub Actions Secrets、Vault 等） |

**macOS（参考）:**
```bash
read -sp "XServer API Key: " X_KEY
security add-generic-password -U -a "apikey" -s "xserver-api" -w "$X_KEY" -l "XServer API Key"
unset X_KEY
# 読み込み
export XSERVER_API_KEY=$(security find-generic-password -s "xserver-api" -w)
```

**Windows PowerShell（参考）:**
```powershell
$apiKey = Read-Host "XServer API キーを入力してください" -AsSecureString
(New-Object PSCredential("xserver-api", $apiKey)) | Export-Clixml -Path "$env:LOCALAPPDATA\xserver-api.xml"
# 読み込み
$XSERVER_API_KEY = (Import-Clixml "$env:LOCALAPPDATA\xserver-api.xml").GetNetworkCredential().Password
```

**Linux / VPS / コンテナ（参考）:**
```bash
# secret-tool が使える場合
read -sp "XServer API Key: " X_KEY
printf %s "$X_KEY" | secret-tool store --label="XServer API Key" service xserver-api account apikey
unset X_KEY
export XSERVER_API_KEY=$(secret-tool lookup service xserver-api account apikey)

# secret-tool が使えない場合（セッション限定）
read -sp "XServer API Key: " XSERVER_API_KEY && export XSERVER_API_KEY
# 同じシェルセッションからエージェントを起動する
```

**サンドボックス型エージェント（Codex 等）の場合:**
サンドボックス内では親シェルの `export` が引き継がれないことがある。
その場合は起動コマンドに直接渡す:
```bash
read -sp "XServer API Key: " K && echo
XSERVER_API_KEY="$K" codex
```

**【エージェント厳守】**
- キーをコマンド引数にリテラルで含めてはならない（`printf %s 'xs_...'`、`echo 'xs_...'` 等は禁止）
- `$XSERVER_API_KEY` が未設定の場合は作業を止め、上記の設定をユーザーに求めて待機する

複数契約を並行運用する場合の運用パターンは「複数契約の並行運用（補足）」セクションを参照。

### 1-5. サーバー情報の取得

```bash
curl -s -X GET "https://api.xserver.ne.jp/v1/server/${SERVERNAME}/server-info" \
  -H "Authorization: Bearer $XSERVER_API_KEY"
```

記録すべき値:
- `ip_address` → DNS 設定用
- `name_servers` → ドメインのネームサーバー設定用（ns1〜ns5.xserver.jp）
- `php_versions` → PHP バージョン選択時に参照
- `db_versions` → MySQL/MariaDB の製品・バージョン確認（サーバー世代により異なる）

SSH 接続情報は `servername` から決定論的に組み立てるため、
`hostname` の記録は不要（詳細は Step 1-6 参照）。

ユーザーが「セットアップして」とだけ依頼した場合は、ここまでを既定範囲として完了する。
完了後は、サイト公開・WordPress インストール・ドメイン/SSL 設定・終了など、
次に進める作業を短く提示してユーザーの指示を待つ。

### 1-6. SSH 設定（ファイルデプロイ時のみ）

XServer の SSH は公開鍵認証のみ対応（パスワード認証は不可）。
SSH の有効化と鍵登録はすべて API 経由で実施する。
SSH の有効化・無効化、国外アクセス制限の変更、公開鍵の追加・無効化・削除は、実行前にユーザー確認を取る。

SSH 接続情報は `servername` から決定論的に組み立てる。追加の API 呼び出しは不要。

- ホスト: `${SERVERNAME}`（初期ドメインそのまま。例: `xs123456.xsrv.jp`）
- ユーザー: `${SERVERNAME%%.*}`（最初のラベル。例: `xs123456`）
- ポート: `10022`（固定）
- 認証: 公開鍵のみ

#### 1-6-1. SSH を有効化

```bash
curl -s -X PUT "https://api.xserver.ne.jp/v1/server/${SERVERNAME}/ssh" \
  -H "Authorization: Bearer $XSERVER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ssh_enabled": true}'
```

#### 1-6-2. ローカル鍵を生成して公開鍵を登録

既定ではローカルで ed25519 鍵を生成し、公開鍵のみ API に登録する。
秘密鍵を API レスポンスとして受け取る `generate: true` は、ローカルで鍵生成できない場合のフォールバックとする。

```bash
XSERVER_SSH_KEY=~/.ssh/xserver_deploy.key

ssh-keygen -t ed25519 -N '' -C "xserver-deploy-${SERVERNAME%%.*}" -f "$XSERVER_SSH_KEY"
chmod 600 "$XSERVER_SSH_KEY"

PUBLIC_KEY=$(cat "${XSERVER_SSH_KEY}.pub")
BODY=$(jq -n --arg public_key "$PUBLIC_KEY" --arg label "deploy" \
  '{public_key: $public_key, label: $label}')

curl -s -X POST "https://api.xserver.ne.jp/v1/server/${SERVERNAME}/ssh/key" \
  -H "Authorization: Bearer $XSERVER_API_KEY" \
  -H "Content-Type: application/json" \
  -d "$BODY"
```

`generate: true` を使う場合、秘密鍵はレスポンスで1回だけ返る。標準出力やログに表示せず、即座に OS セキュアストレージへ保存する。

#### 1-6-3. 接続テスト

```bash
XSERVER_SSH_KEY=${XSERVER_SSH_KEY:-~/.ssh/xserver_deploy.key}
chmod 600 "$XSERVER_SSH_KEY"

ssh -i "$XSERVER_SSH_KEY" -o StrictHostKeyChecking=accept-new \
  -p 10022 "${SERVERNAME%%.*}@${SERVERNAME}" "echo 'SSH接続成功'"
```

※既存の公開鍵を登録する場合は `ssh-keygen` を省略し、`{"public_key": "ssh-ed25519 AAAA...", "label": "deploy"}` を送信する。

---

## Step 2: プロジェクト設定

### 2-1. 公開先の合意（必須）

公開先は AI が独断で決めない。前回セッションの値や保存値も無断で再利用しない。
ユーザーが公開先ドメインを指定していない場合は、必ず以下を確認する。

- 登録済みドメイン: `GET /domain` の一覧
- 登録済みサブドメイン: `GET /subdomain` の一覧
- 初期ドメイン: `${SERVERNAME}` そのもの（API 呼び出し不要）
- 新規追加（独自ドメイン / サブドメイン）も選択肢として提示

公開先が決まったら `document_root` を取得し（独自ドメインは
`GET /domain/{domain}`、サブドメインは `GET /subdomain` 一覧から FQDN マッチ）、
SSH で既存ファイルを確認する。既存サイトがある場合は、上書き・全削除・
サブパス配置のどれにするかをユーザーに確認する。

```bash
ssh -i ~/.ssh/xserver_deploy.key -p 10022 \
  "${SERVERNAME%%.*}@${SERVERNAME}" "ls -la ${DOCUMENT_ROOT}/"
```

### 2-2. `.xserver.json` の作成

プロジェクトルートに `.xserver.json` を作成。`deploy_path` は Step 2-1 で取得した
`document_root` を使う。`.xserver.json` は `.gitignore` に追加すること。

```json
{
  "servername": "xs123456.xsrv.jp",
  "domain": "example.com",
  "deploy_path": "/home/xs123456/example.com/public_html",
  "deploy_source": "./dist"
}
```

---

## Step 3: アプリケーション作成

エックスサーバーは Apache ベースの共用ホスティング。

| 用途 | 推奨構成 |
|------|---------|
| 静的サイト・LP | HTML + Tailwind CSS (CDN) + Alpine.js |
| 動的サイト | PHP（利用可能バージョンは `server-info` の `php_versions` で確認） |
| CMS・ブログ | WordPress（API で自動インストール可能） |
| DB 利用 | MariaDB（サーバーによっては MySQL）。製品とバージョンは `server-info` の `db_versions` で確認 |

制約: Node.js ランタイム不可（デーモン起動不可）。`.htaccess` で Apache 設定可能。

### サイト構築前の合意

複数ページ・独自デザイン・公開まで含む依頼では、着手前にコンセプト、
ページ構成、使用技術、公開先の方針を短く提示し、ユーザーの合意を得てから作成する。
ダミーでよいと言われた場合も、会社名・ページ数・デザイン方針を簡潔に提示する。

---

## Step 4: サーバー設定（API）

Base URL: `https://api.xserver.ne.jp`
全リクエストに `Authorization: Bearer $XSERVER_API_KEY` ヘッダーが必要。

### サーバー情報の確認

各種設定の前に、現在のサーバー情報や利用状況を取得できる。
PHP / DB バージョン、ネームサーバー、IP アドレス、ドメイン所有権確認用トークン、
ディスク使用量や各種設定の件数などを参照する。

```bash
# サーバー情報（PHP/DB バージョン、ネームサーバー、IP、domain_validation_token 等）
curl -s -X GET "https://api.xserver.ne.jp/v1/server/${SERVERNAME}/server-info" \
  -H "Authorization: Bearer $XSERVER_API_KEY"

# 利用状況（ディスク使用量・ファイル数・各種設定件数）
curl -s -X GET "https://api.xserver.ne.jp/v1/server/${SERVERNAME}/server-info/usage" \
  -H "Authorization: Bearer $XSERVER_API_KEY"
```

### ドメイン追加 + SSL

```bash
curl -s -X POST "https://api.xserver.ne.jp/v1/server/${SERVERNAME}/domain" \
  -H "Authorization: Bearer $XSERVER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"domain": "example.com", "ssl": true, "redirect_https": true}'
```

`ssl_status` が `failed_nameserver` の場合、当サービスのネームサーバー（ns1〜ns5.xserver.jp）利用を希望するか確認する。
ドメイン所有権確認が必要な場合は `GET /v1/server/{servername}/server-info` の `domain_validation_token` を使用。

### サブドメイン追加

```bash
curl -s -X POST "https://api.xserver.ne.jp/v1/server/${SERVERNAME}/subdomain" \
  -H "Authorization: Bearer $XSERVER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"subdomain": "blog.example.com", "ssl": true}'
```

### WordPress インストール

`admin_password` はサンプル値を使わず、十分に強固なパスワードを生成する
（例: `openssl rand -base64 24` / `pwgen -s 24 1`）。

```bash
curl -s -X POST "https://api.xserver.ne.jp/v1/server/${SERVERNAME}/wp" \
  -H "Authorization: Bearer $XSERVER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/blog",
    "title": "My Blog",
    "admin_username": "admin",
    "admin_password": "<生成したパスワード>",
    "admin_email": "admin@example.com"
  }'
```

`GET /wp?domain=...` は親ドメインのみ対応で、サブドメインによる絞り込みには
対応していない。サブドメインに入れた WordPress を確認するときは、
`GET /wp` の全件取得、または親ドメインで絞り込んだうえで
`wordpress[].url` を見て対象 URL に一致するものを探す。

### データベース作成

```bash
curl -s -X POST "https://api.xserver.ne.jp/v1/server/${SERVERNAME}/db" \
  -H "Authorization: Bearer $XSERVER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name_suffix": "db01", "character_set": "utf8mb4"}'

curl -s -X POST "https://api.xserver.ne.jp/v1/server/${SERVERNAME}/db/user" \
  -H "Authorization: Bearer $XSERVER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name_suffix": "user01", "password": "<生成したパスワード>"}'

curl -s -X POST "https://api.xserver.ne.jp/v1/server/${SERVERNAME}/db/user/xs123456_user01/grant" \
  -H "Authorization: Bearer $XSERVER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"db_name": "xs123456_db01"}'
```

### DNS / SSL / PHP / Cron / メール / FTP

```bash
# DNS レコード追加
curl -s -X POST "https://api.xserver.ne.jp/v1/server/${SERVERNAME}/dns" \
  -H "Authorization: Bearer $XSERVER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"domain":"example.com","host":"www","type":"A","content":"123.45.67.89","ttl":3600}'

# SSL 個別設定
curl -s -X POST "https://api.xserver.ne.jp/v1/server/${SERVERNAME}/ssl" \
  -H "Authorization: Bearer $XSERVER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"common_name": "example.com"}'

# PHP バージョン変更
curl -s -X PUT "https://api.xserver.ne.jp/v1/server/${SERVERNAME}/php-version/example.com" \
  -H "Authorization: Bearer $XSERVER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"version": "8.3"}'

# Cron 追加
curl -s -X POST "https://api.xserver.ne.jp/v1/server/${SERVERNAME}/cron" \
  -H "Authorization: Bearer $XSERVER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"minute":"0","hour":"3","day":"*","month":"*","weekday":"*","command":"/usr/bin/php /home/xs123456/example.com/public_html/cron.php"}'

# メールアカウント作成
curl -s -X POST "https://api.xserver.ne.jp/v1/server/${SERVERNAME}/mail" \
  -H "Authorization: Bearer $XSERVER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"mail_address":"info@example.com","password":"<生成したパスワード>","quota_mb":2000}'

# FTP アカウント作成
curl -s -X POST "https://api.xserver.ne.jp/v1/server/${SERVERNAME}/ftp" \
  -H "Authorization: Bearer $XSERVER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ftp_account":"deploy@example.com","password":"<生成したパスワード>","directory":"/example.com/public_html"}'
```

### WordPress 削除

WordPress 削除はデフォルト値が項目ごとに揃っていないため事故になりやすい。
削除対象を必ず表示してユーザー確認を得てから、明示的に boolean を送る。

- `delete_db`（デフォルト true）: 関連データベースも削除
- `delete_db_user`（デフォルト false）: 関連 DB ユーザーも削除
- `delete_cron`（デフォルト true）: 関連 Cron も削除

```bash
curl -s -X DELETE "https://api.xserver.ne.jp/v1/server/${SERVERNAME}/wp/${WP_ID}" \
  -H "Authorization: Bearer $XSERVER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"delete_db": true, "delete_db_user": false, "delete_cron": true}'
```

---

## Step 5: ファイルデプロイ

### 認証情報の取得

#### macOS

```bash
XSERVER_API_KEY=$(security find-generic-password -s "xserver-api" -w)
XSERVER_SSH_KEY=~/.ssh/xserver_deploy.key
chmod 600 "$XSERVER_SSH_KEY"
```

#### Windows

```powershell
if (-not (Get-Module -ListAvailable -Name CredentialManager)) {
    Install-Module -Name CredentialManager -Scope CurrentUser -Force
}
$apiCred = Get-StoredCredential -Target "xserver-api"
$XSERVER_API_KEY = $apiCred.GetNetworkCredential().Password
$XSERVER_SSH_KEY = "$HOME\.ssh\xserver_deploy.key"
icacls $XSERVER_SSH_KEY /inheritance:r /grant:r "$($env:USERNAME):R"
```

### rsync でデプロイ

```bash
SERVERNAME=$(jq -r '.servername' .xserver.json)
DEPLOY_PATH=$(jq -r '.deploy_path' .xserver.json)
DEPLOY_SOURCE=$(jq -r '.deploy_source // "."' .xserver.json)

# まず dry-run で削除・更新対象を確認する
rsync -avzn --delete \
  -e "ssh -i $XSERVER_SSH_KEY -p 10022 -o StrictHostKeyChecking=accept-new" \
  --exclude '.git' --exclude 'node_modules' --exclude '.env' \
  --exclude '.DS_Store' --exclude '.xserver.json' \
  ${DEPLOY_SOURCE}/ "${SERVERNAME%%.*}@${SERVERNAME}:${DEPLOY_PATH}/"

rsync -avz --delete \
  -e "ssh -i $XSERVER_SSH_KEY -p 10022 -o StrictHostKeyChecking=accept-new" \
  --exclude '.git' --exclude 'node_modules' --exclude '.env' \
  --exclude '.DS_Store' --exclude '.xserver.json' \
  ${DEPLOY_SOURCE}/ "${SERVERNAME%%.*}@${SERVERNAME}:${DEPLOY_PATH}/"
```

`--delete` を使うため、dry-run の結果をユーザーに示してから本実行すること。

### デプロイ後の確認

```bash
ssh -i "$XSERVER_SSH_KEY" -p 10022 "${SERVERNAME%%.*}@${SERVERNAME}" "ls -la ${DEPLOY_PATH}/"

curl -s "https://api.xserver.ne.jp/v1/server/${SERVERNAME}/error-log?domain=example.com&lines=20" \
  -H "Authorization: Bearer $XSERVER_API_KEY"
```

デプロイ完了後、必ずサイト URL をユーザーに表示する。
URL は `GET /v1/server/{servername}/domain/{domain}` の `url` フィールドで取得できる。

公開後は「修正したい点や追加で対応したいことはありますか？」と確認し、ユーザーの指示を待つ。

---

## API エンドポイント一覧

このスキルでカバーする API:

- API キー情報: 認証中の API キー情報（有効期限・権限種別）の取得
- サーバー情報: ホスト名 / IP アドレス / 利用可能 PHP・DB バージョン / ネームサーバー / 利用状況の取得
- ドメイン設定: 追加 / 設定変更 / 削除 / 初期化
- サブドメイン設定: 追加 / 設定変更 / 削除
- SSL 設定: 無料独自 SSL の ON / OFF
- DNS レコード設定: 取得 / 追加 / 変更 / 削除
- メールアカウント設定: 作成 / 設定変更 / 削除 / 転送設定
- メール振り分け設定: 追加 / 削除
- WordPress 簡単インストール: インストール / 設定変更 / アンインストール
- MySQL 設定: DB / ユーザーの作成・削除 / アクセス権限の設定
- FTP アカウント設定: 作成 / 設定変更 / 削除
- Cron 設定: 追加 / 設定変更 / 削除
- PHP バージョン設定: ドメインごとの確認・変更
- SSH 設定: 有効化 / 国外アクセス制限 / 公開鍵の登録（手動・自動生成）・有効化・削除
- アクセスログ / エラーログ: 取得

詳細なメソッド・パス・パラメータ・レスポンス仕様は上記 OpenAPI 仕様を参照する。
次のいずれかに該当する場合も OpenAPI 仕様を参照する。

- ここに掲載がない機能を使いたい
- 想定通りのレスポンスにならず、スキル記載が古い可能性がある
- 「こんな API はあるか？」を確認したい

## レート制限

API にはリクエスト数・同時接続数のレート制限がある。
上限はプランや契約状態により異なるため固定値を前提にしない。
`X-RateLimit-*` / `X-RateLimit-Concurrent-*` ヘッダーで現在の制限値と残数を確認し、
HTTP 429 時は `Retry-After` 秒だけ待ってから再試行する。

---

## 複数契約の並行運用（補足）

スキル本体は1契約利用を既定としている。複数のエックスサーバー契約を並行運用する
場合は、Keychain ラベルや SSH キーファイル名に server_id（servername の最初の
ラベル。例: `xs391946`）を付与して契約ごとに分離する運用を推奨する。

例:

- ラベル: `xserver-api-xs391946` / `xserver-ssh-key-xs391946`
- ファイル: `~/.ssh/xserver_deploy_xs391946.key`

利用するサーバーに合わせて環境変数 `XSERVER_API_KEY` をシェルで切り替える。
プロジェクトディレクトリごとに `.xserver.json` を置けば、ディレクトリ移動時に
適切な `servername` を自動で読み取れる運用になる。

## セキュリティガイドライン

- API キー・秘密鍵は OS セキュアストレージのみに保存。平文ファイルへの永続保存は禁止
- 秘密鍵を一時ファイルに書き出す場合はパーミッション 600 必須、使用後は削除
- `.env`、`.xserver.json`、`~/.ssh/xserver_deploy*.key` はデプロイから除外
- 各種パスワードはサンプル値を使わず、十分に強力なものを生成して設定する
- 破壊的操作（次セクション参照）は実行前に必ずユーザー確認を取る

## 破壊的操作

DELETE 系・`POST /domain/{domain}/reset`・`delete_files: true`・
`forwarding_addresses: []` での転送クリア・`rsync --delete` は
実行前に対象と影響範囲（戻せないこと）をユーザーに表示し、明示的合意を得る。

WordPress 削除は DB / DBユーザー / Cron の削除フラグを個別確認する。

## API 共通注意

- 日本語ドメインを path parameter に渡す場合は Punycode に変換する
- メールアドレスなど `@` を含む path parameter は URL encode する（例: `info%40example.com`）
- DELETE で requestBody が必要な場合は `curl -X DELETE ... -H "Content-Type: application/json" -d '...'` の形で送る

## トラブルシューティング

| 症状 | 対処 |
|------|------|
| HTTP 401 | API キーの有効期限切れ。XServer アカウントで再発行しセキュアストレージを更新 |
| HTTP 403（IPアドレス） | API キーに IP 制限が設定されている。許可IPリストに現在のIPを追加 |
| ドメイン所有権確認エラー | `domain_validation_token` で TXT レコード `_xserver-verify.{domain}` を設定し DNS 反映後に再実行 |
| SSL `failed_nameserver` | 当サービスのネームサーバー利用を希望する場合は ns1〜ns5.xserver.jp への変更を案内。外部 DNS を維持したい場合は API ではなくサーバーパネルから無料 SSL 設定を案内 |
| SSH 接続エラー | `GET /v1/server/{servername}/ssh` で SSH が有効か、公開鍵が登録されているか確認。ポートは 10022 |
| HTTP 429 | レート制限超過。1 秒以上の間隔を空けてリトライ |

## 認証情報の管理

ローカルに保存した API キー・秘密鍵の確認・削除は OS 標準コマンドで行う
（macOS: `security find-generic-password` / `delete-generic-password`、
Windows: `cmdkey /list` / `/delete`、Linux: `secret-tool lookup` / `clear`、`pass`）。
ラベルは `xserver-api` / `xserver-ssh-key` で操作する。

サーバー側に登録済みの公開鍵は `GET /v1/server/{servername}/ssh/key` で一覧、
`DELETE /v1/server/{servername}/ssh/key/{key_id}` で削除する。
