Qwen Cloud Deploy Quick Path 1. Route the task — Match to one of 4 modes: Full-Stack Deploy · Hot Update · Delete · HTTPS Setup. 2. Deploy (default) — Execute steps 1→14 strictly in order, no skipping/reordering; gates and skippable steps are in "Execution order". 3. Confirm cost before creating anything — Show hourly price in USD, get user confirmation. 4. Record state — On success write . Scope | In Scope | Out of Scope | |----------|--------------| | Local project / Git → Alibaba Cloud International | China site → use | | Full-stack ROS, hot update, cleanup | AWS/GCP/Azure/other clouds | |…

\n InstanceType:\n Type: String\n ImageId:\n Type: String\n Default: aliyun_3_x64_20G_alibase_20240528.vhd\n Password:\n Type: String\n NoEcho: true\n MinLength: 8\n MaxLength: 30\n SystemDiskSize:\n Type: Number\n Default: 40\n MinValue: 20\n MaxValue: 500\n ZoneId:\n Type: String\n Description: Availability zone ID (the ECS ∩ RDS intersection zone, see reference/deploy/08_check_stock.md)\n AppPort:\n Type: Number\n Default: 8080\n DbInstanceClass:\n Type: String\n Description: RDS MySQL instance class\n DbInstanceStorage:\n Type: Number\n MinValue: 20\n MaxValue: 6000\n Description: RDS storage size in GB\n DbName:\n Type: String\n Default: appdb\n AllowedPattern: '^[a-z][a-z0-9_]{0,62}

Qwen Cloud Deploy Quick Path 1. Route the task — Match to one of 4 modes: Full-Stack Deploy · Hot Update · Delete · HTTPS Setup. 2. Deploy (default) — Execute steps 1→14 strictly in order, no skipping/reordering; gates and skippable steps are in "Execution order". 3. Confirm cost before creating anything — Show hourly price in USD, get user confirmation. 4. Record state — On success write . Scope | In Scope | Out of Scope | |----------|--------------| | Local project / Git → Alibaba Cloud International | China site → use | | Full-stack ROS, hot update, cleanup | AWS/GCP/Azure/other clouds | |…

\n DbAccount:\n Type: String\n Default: appuser\n AllowedPattern: '^[a-z][a-z0-9_]{0,15}

Qwen Cloud Deploy Quick Path 1. Route the task — Match to one of 4 modes: Full-Stack Deploy · Hot Update · Delete · HTTPS Setup. 2. Deploy (default) — Execute steps 1→14 strictly in order, no skipping/reordering; gates and skippable steps are in "Execution order". 3. Confirm cost before creating anything — Show hourly price in USD, get user confirmation. 4. Record state — On success write . Scope | In Scope | Out of Scope | |----------|--------------| | Local project / Git → Alibaba Cloud International | China site → use | | Full-stack ROS, hot update, cleanup | AWS/GCP/Azure/other clouds | |…

\n DbPassword:\n Type: String\n NoEcho: true\n MinLength: 8\n MaxLength: 32\n Description: RDS account password (8-32 characters, must include uppercase + lowercase + digits + special characters)\n\nResources:\n Vpc:\n Type: ALIYUN::ECS::VPC\n Properties:\n VpcName:\n Fn::Sub: qwencloud-${AppName}-vpc\n CidrBlock: 10.0.0.0/16\n Tags:\n - Key: from\n Value: qwencloud\n - Key: qwencloud-appName\n Value:\n Ref: AppName\n\n VSwitch:\n Type: ALIYUN::ECS::VSwitch\n Properties:\n VpcId:\n Ref: Vpc\n ZoneId:\n Ref: ZoneId\n CidrBlock: 10.0.1.0/24\n VSwitchName:\n Fn::Sub: qwencloud-${AppName}-vsw\n Tags:\n - Key: from\n Value: qwencloud\n\n SecurityGroup:\n Type: ALIYUN::ECS::SecurityGroup\n Properties:\n SecurityGroupName:\n Fn::Sub: qwencloud-${AppName}-sg\n VpcId:\n Ref: Vpc\n SecurityGroupIngress:\n - PortRange: 80/80\n Priority: 1\n IpProtocol: tcp\n SourceCidrIp: 0.0.0.0/0\n NicType: intranet\n - PortRange: 443/443\n Priority: 1\n IpProtocol: tcp\n SourceCidrIp: 0.0.0.0/0\n NicType: intranet\n Tags:\n - Key: from\n Value: qwencloud\n\n RdsInstance:\n Type: ALIYUN::RDS::DBInstance\n Properties:\n Engine: MySQL\n EngineVersion: '8.0'\n DBInstanceClass:\n Ref: DbInstanceClass\n DBInstanceStorage:\n Ref: DbInstanceStorage\n DBInstanceStorageType: cloud_essd\n PayType: Postpaid\n DBInstanceDescription:\n Fn::Sub: qwencloud-${AppName}-rds\n VpcId:\n Ref: Vpc\n VSwitchId:\n Ref: VSwitch\n ZoneId:\n Ref: ZoneId\n SecurityIPList: 10.0.0.0/16\n DeletionProtection: false\n Tags:\n from: qwencloud\n\n RdsDatabase:\n Type: ALIYUN::RDS::Database\n Properties:\n DBInstanceId:\n Ref: RdsInstance\n DBName:\n Ref: DbName\n CharacterSetName: utf8mb4\n DependsOn: RdsInstance\n\n RdsAccount:\n Type: ALIYUN::RDS::Account\n Properties:\n DBInstanceId:\n Ref: RdsInstance\n AccountName:\n Ref: DbAccount\n AccountPassword:\n Ref: DbPassword\n AccountType: Normal\n DependsOn: RdsDatabase\n\n RdsAccountPrivilege:\n Type: ALIYUN::RDS::AccountPrivilege\n Properties:\n DBInstanceId:\n Ref: RdsInstance\n AccountName:\n Ref: DbAccount\n DBName:\n Ref: DbName\n AccountPrivilege: ReadWrite\n DependsOn: RdsAccount\n\n EcsInstance:\n Type: ALIYUN::ECS::InstanceGroup\n Properties:\n ImageId:\n Ref: ImageId\n InstanceType:\n Ref: InstanceType\n InstanceChargeType: PostPaid\n Password:\n Ref: Password\n SecurityGroupId:\n Ref: SecurityGroup\n VSwitchId:\n Ref: VSwitch\n VpcId:\n Ref: Vpc\n InstanceName:\n Fn::Sub: qwencloud-${AppName}-ecs-[1,2]\n HostName:\n Fn::Sub: qwencloud-${AppName}-ecs-[1,2]\n MaxAmount: 1\n MinAmount: 1\n SystemDiskCategory: cloud_essd\n SystemDiskSize:\n Ref: SystemDiskSize\n AllocatePublicIP: false\n UserData:\n Fn::Sub:\n - |\n #!/bin/bash\n set -euxo pipefail\n # The bootstrap log may contain database connection details; create it\n # with tight permissions before writing (the default umask yields 644,\n # readable by any local user).\n install -m 600 /dev/null /var/log/qwencloud-bootstrap.log 2>/dev/null || \\\n { touch /var/log/qwencloud-bootstrap.log; chmod 600 /var/log/qwencloud-bootstrap.log; }\n exec >> /var/log/qwencloud-bootstrap.log 2>&1\n echo \"[$(date -u +%FT%TZ)] === qwencloud bootstrap (with RDS) start ===\"\n\n # Disable xtrace while writing/loading the password, otherwise -x\n # echoes DB_PASSWORD in cleartext into the log.\n set +x\n mkdir -p /etc/qwencloud\n cat > /etc/qwencloud/db.env \u003c\u003cDBENV\n DATABASE_URL=\"mysql://${DbAccount}:${DbPassword}@${RdsAddr}:${RdsPort}/${DbName}\"\n DB_HOST=\"${RdsAddr}\"\n DB_PORT=\"${RdsPort}\"\n DB_NAME=\"${DbName}\"\n DB_USER=\"${DbAccount}\"\n DB_PASSWORD=\"${DbPassword}\"\n DBENV\n chmod 600 /etc/qwencloud/db.env\n\n set -a\n . /etc/qwencloud/db.env\n set +a\n set -x\n echo \"[bootstrap] /etc/qwencloud/db.env written (contents omitted)\"\n\n # ↓↓↓ generate_template.py injects base64-encoded bootstrap script (decoded and sourced at runtime, inheriting db.env) ↓↓↓\n __USERDATA_BODY__\n - RdsAddr:\n Fn::GetAtt: [RdsInstance, InnerConnectionString]\n RdsPort:\n Fn::GetAtt: [RdsInstance, InnerPort]\n Tags:\n - Key: from\n Value: qwencloud\n - Key: qwencloud-appName\n Value:\n Ref: AppName\n DependsOn: RdsAccountPrivilege\n\n Eip:\n Type: ALIYUN::VPC::EIP\n Properties:\n Name:\n Fn::Sub: qwencloud-${AppName}-eip\n InternetChargeType: PayByTraffic\n Bandwidth: 5\n Tags:\n - Key: from\n Value: qwencloud\n\n EipAssoc:\n Type: ALIYUN::VPC::EIPAssociation\n Properties:\n AllocationId:\n Ref: Eip\n InstanceId:\n Fn::Select:\n - 0\n - Fn::GetAtt:\n - EcsInstance\n - InstanceIds\n\nOutputs:\n PublicIp:\n Description: Public access IP (static http://\u003cIP>/, app http://\u003cIP>/api/)\n Value:\n Fn::GetAtt:\n - Eip\n - EipAddress\n EcsInstanceIds:\n Description: ECS instance ID list\n Value:\n Fn::GetAtt:\n - EcsInstance\n - InstanceIds\n EcsPrivateIps:\n Value:\n Fn::GetAtt:\n - EcsInstance\n - PrivateIps\n SecurityGroupId:\n Description: ECS security group ID (ingress rule check / authorize)\n Value:\n Fn::GetAtt:\n - SecurityGroup\n - SecurityGroupId\n EipAllocationId:\n Description: EIP allocation ID (EIP status query / re-bind)\n Value:\n Fn::GetAtt:\n - Eip\n - AllocationId\n DbInstanceId:\n Description: RDS instance ID\n Value:\n Ref: RdsInstance\n DbConnectionAddress:\n Description: RDS internal connection address\n Value:\n Fn::GetAtt:\n - RdsInstance\n - InnerConnectionString\n DbPort:\n Description: RDS internal port\n Value:\n Fn::GetAtt:\n - RdsInstance\n - InnerPort\n DbAccount:\n Value:\n Ref: DbAccount\n StackName:\n Value:\n Ref: ALIYUN::StackName\n","content_type":"application/yaml; charset=utf-8","language":"yaml","size":7951,"content_sha256":"d384e61bb86e1f022cfea5050215c2f3b3964ee8f7a72d9ee8e86123c8937569"},{"filename":"templates/ros_single.yaml","content":"ROSTemplateFormatVersion: '2015-09-01'\nDescription: 'qwencloud single-host deployment: 1 ECS + EIP + VPC + SecurityGroup. Static hosting + app service co-located on one VM.'\n\nParameters:\n AppName:\n Type: String\n Description: App name (used for resource naming), lowercase alphanumeric and hyphens only\n Default: app\n AllowedPattern: '^[a-z][a-z0-9-]{0,30}

Qwen Cloud Deploy Quick Path 1. Route the task — Match to one of 4 modes: Full-Stack Deploy · Hot Update · Delete · HTTPS Setup. 2. Deploy (default) — Execute steps 1→14 strictly in order, no skipping/reordering; gates and skippable steps are in "Execution order". 3. Confirm cost before creating anything — Show hourly price in USD, get user confirmation. 4. Record state — On success write . Scope | In Scope | Out of Scope | |----------|--------------| | Local project / Git → Alibaba Cloud International | China site → use | | Full-stack ROS, hot update, cleanup | AWS/GCP/Azure/other clouds | |…

\n InstanceType:\n Type: String\n Description: ECS instance type\n ImageId:\n Type: String\n Default: aliyun_3_x64_20G_alibase_20240528.vhd\n Description: OS image. Default is Alibaba Cloud Linux 3 x86_64.\n Password:\n Type: String\n NoEcho: true\n Description: ECS login password (8-30 characters, must include uppercase + lowercase + digits)\n MinLength: 8\n MaxLength: 30\n SystemDiskSize:\n Type: Number\n Default: 40\n MinValue: 20\n MaxValue: 500\n ZoneId:\n Type: String\n Description: Availability zone ID (the in-stock zone selected in step 6)\n AppPort:\n Type: Number\n Default: 8080\n Description: App service listening port (reverse-proxied by Nginx to /api/)\n UserDataScript:\n Type: String\n Description: Bootstrap script (plaintext, ROS will auto base64-encode it)\n Default: |\n #!/bin/bash\n echo \"no userdata provided\" > /var/log/qwencloud-bootstrap.log\n\nResources:\n Vpc:\n Type: ALIYUN::ECS::VPC\n Properties:\n VpcName:\n Fn::Sub: qwencloud-${AppName}-vpc\n CidrBlock: 10.0.0.0/16\n Tags:\n - Key: from\n Value: qwencloud\n - Key: qwencloud-appName\n Value:\n Ref: AppName\n\n VSwitch:\n Type: ALIYUN::ECS::VSwitch\n Properties:\n VpcId:\n Ref: Vpc\n ZoneId:\n Ref: ZoneId\n CidrBlock: 10.0.1.0/24\n VSwitchName:\n Fn::Sub: qwencloud-${AppName}-vsw\n Tags:\n - Key: from\n Value: qwencloud\n\n SecurityGroup:\n Type: ALIYUN::ECS::SecurityGroup\n Properties:\n SecurityGroupName:\n Fn::Sub: qwencloud-${AppName}-sg\n VpcId:\n Ref: Vpc\n SecurityGroupIngress:\n - PortRange: 80/80\n Priority: 1\n IpProtocol: tcp\n SourceCidrIp: 0.0.0.0/0\n NicType: intranet\n - PortRange: 443/443\n Priority: 1\n IpProtocol: tcp\n SourceCidrIp: 0.0.0.0/0\n NicType: intranet\n Tags:\n - Key: from\n Value: qwencloud\n\n EcsInstance:\n Type: ALIYUN::ECS::InstanceGroup\n Properties:\n ImageId:\n Ref: ImageId\n InstanceType:\n Ref: InstanceType\n InstanceChargeType: PostPaid\n Password:\n Ref: Password\n SecurityGroupId:\n Ref: SecurityGroup\n VSwitchId:\n Ref: VSwitch\n VpcId:\n Ref: Vpc\n InstanceName:\n Fn::Sub: qwencloud-${AppName}-ecs-[1,2]\n HostName:\n Fn::Sub: qwencloud-${AppName}-ecs-[1,2]\n MaxAmount: 1\n MinAmount: 1\n SystemDiskCategory: cloud_essd\n SystemDiskSize:\n Ref: SystemDiskSize\n AllocatePublicIP: false\n UserData:\n Ref: UserDataScript\n Tags:\n - Key: from\n Value: qwencloud\n - Key: qwencloud-appName\n Value:\n Ref: AppName\n\n Eip:\n Type: ALIYUN::VPC::EIP\n Properties:\n Name:\n Fn::Sub: qwencloud-${AppName}-eip\n InternetChargeType: PayByTraffic\n Bandwidth: 5\n Tags:\n - Key: from\n Value: qwencloud\n\n EipAssoc:\n Type: ALIYUN::VPC::EIPAssociation\n Properties:\n AllocationId:\n Ref: Eip\n InstanceId:\n Fn::Select:\n - 0\n - Fn::GetAtt:\n - EcsInstance\n - InstanceIds\n\nOutputs:\n PublicIp:\n Description: Public access IP (static http://\u003cIP>/, app http://\u003cIP>/api/)\n Value:\n Fn::GetAtt:\n - Eip\n - EipAddress\n EcsInstanceIds:\n Description: ECS instance ID list\n Value:\n Fn::GetAtt:\n - EcsInstance\n - InstanceIds\n EcsPrivateIps:\n Description: ECS private IP list\n Value:\n Fn::GetAtt:\n - EcsInstance\n - PrivateIps\n SecurityGroupId:\n Description: ECS security group ID (ingress rule check / authorize)\n Value:\n Fn::GetAtt:\n - SecurityGroup\n - SecurityGroupId\n EipAllocationId:\n Description: EIP allocation ID (EIP status query / re-bind)\n Value:\n Fn::GetAtt:\n - Eip\n - AllocationId\n StackName:\n Value:\n Ref: ALIYUN::StackName\n","content_type":"application/yaml; charset=utf-8","language":"yaml","size":4437,"content_sha256":"a84b167a583f9de4d64316ee8cf3102c03cd083844773022eb67e8e864650d4d"},{"filename":"templates/userdata/docker.sh","content":"#!/bin/bash\n# qwencloud · Docker app bootstrap\n# Placeholders:\n# __APP_ARTIFACT_URL__ OSS signed URL of app image tar.gz (docker save output) or docker-compose.yml + build context tar.gz\n# __APP_MODE__ docker-image | docker-compose\n# __APP_PORT__ App container listening port (reverse-proxied by Nginx)\n# __APP_IMAGE_NAME__ Image name:tag after docker load in docker-image mode (e.g. myapp:latest)\n# __APP_NAME__ Service name (systemd unit / container name)\nset -euxo pipefail\n\nLOG=/var/log/qwencloud-bootstrap.log\nexec >> \"$LOG\" 2>&1\necho \"[$(date -u +%FT%TZ)] === qwencloud docker bootstrap start ===\"\n\n# 1. Install Docker\nif ! command -v docker >/dev/null 2>&1; then\n if command -v dnf >/dev/null 2>&1; then\n dnf install -y docker\n elif command -v yum >/dev/null 2>&1; then\n yum install -y docker\n elif command -v apt-get >/dev/null 2>&1; then\n apt-get update && apt-get install -y docker.io\n fi\nfi\nsystemctl enable docker\nsystemctl start docker\n\nAPP_URL=\"__APP_ARTIFACT_URL__\"\nAPP_MODE=\"__APP_MODE__\"\nAPP_PORT=\"__APP_PORT__\"\nIMAGE_NAME=\"__APP_IMAGE_NAME__\"\nAPP_NAME=\"__APP_NAME__\"\n\nmkdir -p /opt/qwencloud\ncd /opt/qwencloud\ncurl -fsSL \"$APP_URL\" -o app.tar.gz\n\n# If RDS bootstrap wrote db.env, mount it into the container at startup\nDB_ENV_OPT=\"\"\n[ -f /etc/qwencloud/db.env ] && DB_ENV_OPT=\"--env-file /etc/qwencloud/db.env\"\n\nif [ \"$APP_MODE\" = \"docker-image\" ]; then\n # Extract and docker load\n tar -xzf app.tar.gz\n # After docker load, make sure the image tag matches IMAGE_NAME: the tag baked\n # into the artifact tar may differ from IMAGE_NAME, in which case the unit's\n # ExecStart would fail to find / run the wrong image. Retag based on the load result.\n LOAD_OUT=$(docker load -i image.tar)\n echo \"$LOAD_OUT\"\n LOADED_REF=$(echo \"$LOAD_OUT\" | sed -n 's/^Loaded image: //p' | head -1)\n [ -z \"$LOADED_REF\" ] && LOADED_REF=$(echo \"$LOAD_OUT\" | sed -n 's/^Loaded image ID: //p' | head -1)\n if [ -n \"$LOADED_REF\" ] && [ \"$LOADED_REF\" != \"${IMAGE_NAME}\" ]; then\n docker tag \"$LOADED_REF\" \"${IMAGE_NAME}\"\n fi\n # Write systemd unit for persistent management\n cat > /etc/systemd/system/${APP_NAME}.service \u003c\u003cUNIT\n[Unit]\nDescription=${APP_NAME} app container\nAfter=docker.service\nRequires=docker.service\n\n[Service]\nRestart=always\nExecStartPre=-/usr/bin/docker rm -f ${APP_NAME}\nExecStart=/usr/bin/docker run --rm --name ${APP_NAME} -p ${APP_PORT}:${APP_PORT} ${DB_ENV_OPT} ${IMAGE_NAME}\nExecStop=/usr/bin/docker stop ${APP_NAME}\n\n[Install]\nWantedBy=multi-user.target\nUNIT\n systemctl daemon-reload\n systemctl enable ${APP_NAME}\n systemctl restart ${APP_NAME}\n\nelif [ \"$APP_MODE\" = \"docker-compose\" ]; then\n # Extract (contains docker-compose.yml and build context or pre-built image tar)\n tar -xzf app.tar.gz\n # Install docker compose plugin (if not already available)\n if ! docker compose version >/dev/null 2>&1; then\n mkdir -p /usr/local/lib/docker/cli-plugins\n curl -fsSL https://github.com/docker/compose/releases/latest/download/docker-compose-linux-x86_64 \\\n -o /usr/local/lib/docker/cli-plugins/docker-compose\n chmod +x /usr/local/lib/docker/cli-plugins/docker-compose\n fi\n # compose auto-loads .env from the same directory; if RDS env exists, export it to .env.\n # db.env is 0600 (holds the DB password); use install -m 600 to preserve perms,\n # otherwise a plain cp lands it as 0644 and exposes the secret to other local users.\n if [ -f /etc/qwencloud/db.env ]; then\n install -m 600 /etc/qwencloud/db.env ./.env\n fi\n docker compose -f docker-compose.yml up -d\nfi\n\necho \"[$(date -u +%FT%TZ)] docker app up\"\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":3623,"content_sha256":"d27714c3ef38a0c204085d998567025872da73b23f54c73d39518d97287ddd16"},{"filename":"templates/userdata/nginx_proxy.sh","content":"#!/bin/bash\n# qwencloud · Nginx full reverse proxy to app (for Flask/Django/Express SSR and other server-rendered apps)\n# This snippet is injected into ECS UserData header by generate_template.py.\n# Placeholders (replaced by generate_template.py):\n# __APP_PORT__ App service listening port (e.g. 5000)\nset -euxo pipefail\n\nLOG=/var/log/qwencloud-bootstrap.log\nexec > >(tee -a \"$LOG\") 2>&1\necho \"[$(date -u +%FT%TZ)] === qwencloud nginx (proxy) bootstrap start ===\"\n\n# 1. Install Nginx\nif ! command -v nginx >/dev/null 2>&1; then\n if command -v dnf >/dev/null 2>&1; then dnf install -y nginx\n elif command -v yum >/dev/null 2>&1; then yum install -y nginx\n elif command -v apt-get >/dev/null 2>&1; then apt-get update && apt-get install -y nginx\n else echo \"no supported package manager\"; exit 1\n fi\nfi\n\n# 2. Write site config: all requests reverse-proxied to app\ncat > /etc/nginx/conf.d/qwencloud.conf \u003c\u003cNGINX\nserver {\n listen 80 default_server;\n server_name _;\n\n location / {\n proxy_pass http://127.0.0.1:__APP_PORT__;\n proxy_set_header Host \\$host;\n proxy_set_header X-Real-IP \\$remote_addr;\n proxy_set_header X-Forwarded-For \\$proxy_add_x_forwarded_for;\n proxy_set_header X-Forwarded-Proto \\$scheme;\n proxy_read_timeout 60s;\n proxy_connect_timeout 10s;\n }\n\n location = /healthz { return 200 \"ok\\n\"; }\n}\nNGINX\n\n# Remove default server (avoid conflicts)\n[ -f /etc/nginx/conf.d/default.conf ] && mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.bak || true\n\nnginx -t\nsystemctl enable nginx\nsystemctl restart nginx\n\necho \"[$(date -u +%FT%TZ)] nginx (proxy) ready\"\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":1660,"content_sha256":"d45883ddbf478359b237ac9a92401df7bfe77126fc21debd89a577f4964ee81e"},{"filename":"templates/userdata/nginx_static_proxy.sh","content":"#!/bin/bash\n# qwencloud · Nginx static hosting + /api/ reverse proxy to app\n# This snippet is injected into ECS UserData header by generate_template.py.\n# Placeholders (replaced by generate_template.py):\n# __STATIC_ARTIFACT_URL__ OSS signed URL of static dist archive (http GET)\n# __APP_PORT__ App service listening port (e.g. 8080)\nset -euxo pipefail\n\nLOG=/var/log/qwencloud-bootstrap.log\nexec > >(tee -a \"$LOG\") 2>&1\necho \"[$(date -u +%FT%TZ)] === qwencloud nginx bootstrap start ===\"\n\n# 1. Install Nginx\nif ! command -v nginx >/dev/null 2>&1; then\n if command -v dnf >/dev/null 2>&1; then dnf install -y nginx\n elif command -v yum >/dev/null 2>&1; then yum install -y nginx\n elif command -v apt-get >/dev/null 2>&1; then apt-get update && apt-get install -y nginx\n else echo \"no supported package manager\"; exit 1\n fi\nfi\n\n# 2. Pull static build artifacts (if any)\n# Note: STATIC_URL is replaced by generate_template.py before packaging: real signed URL if artifacts exist, empty string if no static\nSTATIC_URL='__STATIC_ARTIFACT_URL__'\nmkdir -p /var/www/static\nif [ -n \"$STATIC_URL\" ]; then\n curl -fsSL \"$STATIC_URL\" -o /tmp/static.tar.gz\n tar -xzf /tmp/static.tar.gz -C /var/www/static --strip-components=0\n rm -f /tmp/static.tar.gz\nelse\n cat > /var/www/static/index.html \u003c\u003c'HTML'\n\u003c!doctype html>\u003cmeta charset=utf-8>\u003ctitle>qwencloud\u003c/title>\n\u003ch1>ECS is up. Awaiting static artifact.\u003c/h1>\nHTML\nfi\n\n# 3. Write site config: port 80 root points to static, /api/ reverse-proxies to app\ncat > /etc/nginx/conf.d/qwencloud.conf \u003c\u003cNGINX\nserver {\n listen 80 default_server;\n server_name _;\n root /var/www/static;\n index index.html;\n\n location / {\n try_files \\$uri \\$uri/ /index.html;\n }\n\n location /api/ {\n proxy_pass http://127.0.0.1:__APP_PORT__;\n proxy_set_header Host \\$host;\n proxy_set_header X-Real-IP \\$remote_addr;\n proxy_set_header X-Forwarded-For \\$proxy_add_x_forwarded_for;\n proxy_read_timeout 60s;\n }\n\n location = /healthz { return 200 \"ok\\n\"; }\n}\nNGINX\n\n# Remove default server (avoid conflicts)\n[ -f /etc/nginx/conf.d/default.conf ] && mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.bak || true\n\nnginx -t\nsystemctl enable nginx\nsystemctl restart nginx\n\necho \"[$(date -u +%FT%TZ)] nginx ready\"\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":2313,"content_sha256":"2e92ecdb08bb5a1055e3571e3ae92c5036e31c9c36f03356c0a1471f84423ace"},{"filename":"templates/userdata/nginx_static.sh","content":"#!/bin/bash\n# qwencloud · Nginx pure static hosting (no app reverse proxy)\n# This snippet is injected into ECS UserData header by generate_template.py.\n# Placeholders (replaced by generate_template.py):\n# __STATIC_ARTIFACT_URL__ OSS signed URL of static dist archive (http GET)\nset -euxo pipefail\n\nLOG=/var/log/qwencloud-bootstrap.log\nexec > >(tee -a \"$LOG\") 2>&1\necho \"[$(date -u +%FT%TZ)] === qwencloud nginx (static) bootstrap start ===\"\n\n# 1. Install Nginx\nif ! command -v nginx >/dev/null 2>&1; then\n if command -v dnf >/dev/null 2>&1; then dnf install -y nginx\n elif command -v yum >/dev/null 2>&1; then yum install -y nginx\n elif command -v apt-get >/dev/null 2>&1; then apt-get update && apt-get install -y nginx\n else echo \"no supported package manager\"; exit 1\n fi\nfi\n\n# 2. Pull static build artifacts (if any)\nSTATIC_URL='__STATIC_ARTIFACT_URL__'\nmkdir -p /var/www/static\nif [ -n \"$STATIC_URL\" ]; then\n curl -fsSL \"$STATIC_URL\" -o /tmp/static.tar.gz\n tar -xzf /tmp/static.tar.gz -C /var/www/static --strip-components=0\n rm -f /tmp/static.tar.gz\nelse\n cat > /var/www/static/index.html \u003c\u003c'HTML'\n\u003c!doctype html>\u003cmeta charset=utf-8>\u003ctitle>qwencloud\u003c/title>\n\u003ch1>ECS is up. Awaiting static artifact.\u003c/h1>\nHTML\nfi\n\n# 3. Write site config: pure static hosting, no app reverse proxy\ncat > /etc/nginx/conf.d/qwencloud.conf \u003c\u003cNGINX\nserver {\n listen 80 default_server;\n server_name _;\n root /var/www/static;\n index index.html;\n\n location / {\n try_files \\$uri \\$uri/ /index.html;\n }\n\n location = /healthz { return 200 \"ok\\n\"; }\n}\nNGINX\n\n# Remove default server (avoid conflicts)\n[ -f /etc/nginx/conf.d/default.conf ] && mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.bak || true\n\nnginx -t\nsystemctl enable nginx\nsystemctl restart nginx\n\necho \"[$(date -u +%FT%TZ)] nginx (static) ready\"\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":1843,"content_sha256":"1b987fcee2139f1483393c9f547f29af48ebe58e49aee32e23455b7e425578f2"},{"filename":"templates/userdata/systemd.sh","content":"#!/bin/bash\n# qwencloud · systemd managed app\n# Placeholders:\n# __APP_ARTIFACT_URL__ OSS signed URL of app artifact tar.gz\n# __APP_RUNTIME__ none | java | node | python\n# __START_COMMAND__ Full startup command (relative to /opt/qwencloud), e.g.\n# ./server / \"python3 app.py\" / \"sh -c 'java -jar /opt/qwencloud/*.jar'\" /\n# \"node server.js\" / \"gunicorn -b :8080 app:app\"\n# __APP_PORT__ App listening port\n# __APP_NAME__ Service name (systemd unit / log file name)\nset -euxo pipefail\n\nLOG=/var/log/qwencloud-bootstrap.log\nexec >> \"$LOG\" 2>&1\necho \"[$(date -u +%FT%TZ)] === qwencloud systemd bootstrap start ===\"\n\nAPP_URL=\"__APP_ARTIFACT_URL__\"\nRUNTIME=\"__APP_RUNTIME__\"\nENTRY=\"__START_COMMAND__\"\nPORT=\"__APP_PORT__\"\nAPP_NAME=\"__APP_NAME__\"\n\n# 1. Install runtime\ncase \"$RUNTIME\" in\n java)\n if ! command -v java >/dev/null 2>&1; then\n if command -v dnf >/dev/null 2>&1; then dnf install -y java-17-openjdk-headless\n else yum install -y java-17-openjdk-headless; fi\n fi\n ;;\n node)\n if ! command -v node >/dev/null 2>&1; then\n # Install Node from the distro's GPG-signed package repos.\n # Order: (1) plain dnf install (on Alibaba Cloud Linux 3, nodejs 20 is a standalone package in\n # alinux3-updates); (2) if no standalone package, enable a nodejs module stream and install;\n # (3) older systems fall back to yum.\n if command -v dnf >/dev/null 2>&1; then\n if ! dnf install -y nodejs npm; then\n if dnf -q module list nodejs >/dev/null 2>&1; then\n dnf -y module reset nodejs || true\n # prefer 20, otherwise fall back to whatever default stream the image offers\n dnf -y module enable nodejs:20 || dnf -y module enable nodejs || true\n dnf install -y nodejs npm\n fi\n fi\n else\n yum install -y nodejs npm\n fi\n fi\n if ! command -v yarn >/dev/null 2>&1; then\n npm install -g yarn\n fi\n ;;\n python)\n if ! command -v python3 >/dev/null 2>&1; then\n yum install -y python3 python3-pip\n fi\n ;;\n none)\n : # No runtime installation needed (static binary, or runtime already exists)\n ;;\n *)\n echo \"[warn] unknown runtime '$RUNTIME', skipping runtime install\"\n ;;\nesac\n\n# 2. Pull artifacts\nmkdir -p /opt/qwencloud\ncd /opt/qwencloud\ncurl -fsSL \"$APP_URL\" -o app.tar.gz\ntar -xzf app.tar.gz\nrm -f app.tar.gz\n\n# python: install dependencies\nif [ \"$RUNTIME\" = \"python\" ] && [ -f requirements.txt ]; then\n python3 -m pip install --no-cache-dir -r requirements.txt\nfi\n# node: install dependencies (when artifact includes package.json)\nif [ \"$RUNTIME\" = \"node\" ] && [ -f package.json ]; then\n yarn install --production\nfi\n\n# 3. Parse startup command\n# ENTRY is the \"full startup command\" and the sole source of the command; the script does NOT\n# inject any interpreter based on runtime — it only resolves the first token (argv[0]) to an\n# absolute path, because systemd ExecStart requires argv[0] to be an absolute path.\n# Whether it's ./server / \"python3 run.py\" / \"java -jar \u003cname>.jar\" / \"gunicorn app:app\",\n# it runs exactly as ENTRY specifies.\nset -- $ENTRY\nARGV0=\"$1\"; shift || true\ncase \"$ARGV0\" in\n /*)\n : ;; # Already an absolute path, use as-is\n */*)\n # Relative path containing / (./server, subdir/app) → build absolute path; cannot use command -v as it returns relative paths as-is\n ARGV0=\"/opt/qwencloud/${ARGV0#./}\"\n chmod +x \"$ARGV0\" 2>/dev/null || true\n ;;\n *)\n if command -v \"$ARGV0\" >/dev/null 2>&1; then\n ARGV0=\"$(command -v \"$ARGV0\")\" # Interpreter/tool on PATH (python3 / node / java / gunicorn ...)\n else\n ARGV0=\"/opt/qwencloud/$ARGV0\" # Executable in the artifact (bare filename, e.g. server)\n chmod +x \"$ARGV0\" 2>/dev/null || true\n fi ;;\nesac\nEXEC=\"$ARGV0 $*\"\n\n# 4. Write systemd unit\ncat > /etc/systemd/system/${APP_NAME}.service \u003c\u003cUNIT\n[Unit]\nDescription=${APP_NAME} app\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nWorkingDirectory=/opt/qwencloud\nEnvironment=PORT=${PORT}\nEnvironmentFile=-/etc/qwencloud/db.env\nExecStart=${EXEC}\nRestart=always\nRestartSec=3\nStandardOutput=append:/var/log/${APP_NAME}.log\nStandardError=append:/var/log/${APP_NAME}.log\n\n[Install]\nWantedBy=multi-user.target\nUNIT\n\nsystemctl daemon-reload\nsystemctl enable ${APP_NAME}\nsystemctl restart ${APP_NAME}\n\necho \"[$(date -u +%FT%TZ)] systemd app up\"\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":4544,"content_sha256":"e3a20e9d55524f1671d9afab08991784b61aeb9dfa664c7b67adeb5e034d548e"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"Qwen Cloud Deploy","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Quick Path","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Route the task","type":"text","marks":[{"type":"strong"}]},{"text":" — Match to one of 4 modes: Full-Stack Deploy · Hot Update · Delete · HTTPS Setup.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Deploy (default)","type":"text","marks":[{"type":"strong"}]},{"text":" — Execute steps 1→14 strictly in order, no skipping/reordering; gates and skippable steps are in ","type":"text"},{"text":"reference/rules/rule_interaction.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" \"Execution order\".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Confirm cost before creating anything","type":"text","marks":[{"type":"strong"}]},{"text":" — Show hourly price in USD, get user confirmation.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Record state","type":"text","marks":[{"type":"strong"}]},{"text":" — On success write ","type":"text"},{"text":".qwencloud-deploy","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Scope","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"In Scope","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Out of Scope","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Local project / Git → Alibaba Cloud International","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"China site → use ","type":"text"},{"text":"qianwenai-deploy","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Full-stack ROS, hot update, cleanup","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"AWS/GCP/Azure/other clouds","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ECS + optional RDS + OSS + public IP","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"K8s/Serverless/container orchestration","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"OAuth/AK auth (no credential collection)","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"—","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Deploy the user's provided code/project","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Reviewing or editing the user's code logic, vouching for code correctness","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"About the user's code","type":"text"}]},{"type":"paragraph","content":[{"text":"This skill builds and deploys the user's provided code/project. It does not review or modify the business logic and does not guarantee the code itself is correct.","type":"text"}]},{"type":"paragraph","content":[{"text":"Bugs, security issues, and any consequences caused by the code once deployed are the user's own; if the code needs changing, the user decides and makes the change themselves.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Assumptions","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"aliyun","type":"text","marks":[{"type":"code_inline"}]},{"text":" CLI 3.x installed; when no valid credential, follow ","type":"text"},{"text":"reference/deploy/01_env_check.md","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Default region ","type":"text"},{"text":"ap-southeast-1","type":"text","marks":[{"type":"code_inline"}]},{"text":" (Singapore).","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Task Routing","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Signal","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Mode","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":".qwencloud-deploy","type":"text","marks":[{"type":"code_inline"}]},{"text":" exists + user says \"update\"","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Hot Update","type":"text","marks":[{"type":"strong"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":".qwencloud-deploy","type":"text","marks":[{"type":"code_inline"}]},{"text":" exists + \"delete\"/\"cleanup\"","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Delete","type":"text","marks":[{"type":"strong"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\"bind domain\"/\"HTTPS\"/\"SSL\" (deployment exists)","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"HTTPS Setup","type":"text","marks":[{"type":"strong"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Git URL or local project (no existing deployment)","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Full-Stack Deploy","type":"text","marks":[{"type":"strong"}]}]}]}]}]},{"type":"paragraph","content":[{"text":"On trigger, display welcome message first (see ","type":"text"},{"text":"reference/rules/rule_interaction.md","type":"text","marks":[{"type":"code_inline"}]},{"text":").","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Full-Stack Deploy (Steps 1–14)","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Phase 1 · Preparation","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Step","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Action","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Reference","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"1","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Environment check","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/deploy/01_env_check.md","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"2","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Git clone (if Git URL)","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/deploy/02_git_clone.md","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"3","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Project analysis","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/deploy/03_analyze_project.md","type":"text","marks":[{"type":"code_inline"}]}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Phase 2 · Resource Planning","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Step","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Action","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Reference","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"4","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Existing deployment scan","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/deploy/04_check_existing.md","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"5","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Database identification","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/deploy/05_database.md","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"6","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ECS instance type selection","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/deploy/06_instance_type.md","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"7","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Generate ROS template","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/deploy/07_generate_template.md","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"8","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Stock check","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/deploy/08_check_stock.md","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"9","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Template validation + cost estimate","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/deploy/09_estimate_cost.md","type":"text","marks":[{"type":"code_inline"}]}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Phase 3 · Execution","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Step","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Action","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Reference","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"10","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Upload artifacts + regenerate template","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/deploy/10_upload_artifacts.md","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"11","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Create stack","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/deploy/11_create_stack.md","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"12","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Wait for terminal state + health check","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/deploy/12_wait_stack.md","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"13","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Record state","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/deploy/13_record_state.md","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"14","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Append application dossier","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/deploy/14_app_timeline.md","type":"text","marks":[{"type":"code_inline"}]}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Hot Update","type":"text"}]},{"type":"paragraph","content":[{"text":"Trigger","type":"text","marks":[{"type":"strong"}]},{"text":": ","type":"text"},{"text":".qwencloud-deploy","type":"text","marks":[{"type":"code_inline"}]},{"text":" exists + user wants to update code. IP unchanged.","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Step","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Action","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Reference","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"U1","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Build + upload new artifacts","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/deploy/10_upload_artifacts.md","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"U2","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Deliver update (Cloud Assistant)","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/hotfix/update_app.md","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"U3","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Health check + update state","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/hotfix/update_app.md","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"U4","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Append application dossier (","type":"text"},{"text":"event=hotfix","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/deploy/14_app_timeline.md","type":"text","marks":[{"type":"code_inline"}]}]}]}]}]},{"type":"paragraph","content":[{"text":"Update script template: ","type":"text"},{"text":"reference/hotfix/update_recipe.md","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Delete / Cleanup","type":"text"}]},{"type":"paragraph","content":[{"text":"Trigger","type":"text","marks":[{"type":"strong"}]},{"text":": User says \"delete\", \"cleanup\", \"release resources\".","type":"text"}]},{"type":"blockquote","content":[{"type":"paragraph","content":[{"text":"⚠️ Irreversible — confirm twice. With RDS: warn about data loss.","type":"text"}]}]},{"type":"blockquote","content":[{"type":"paragraph","content":[{"text":"🚫 Never manually delete individual resources — only use ","type":"text"},{"text":"delete_stack.sh","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"paragraph","content":[{"text":"See ","type":"text"},{"text":"reference/cleanup/delete_stack.md","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"HTTPS Setup (Optional)","type":"text"}]},{"type":"paragraph","content":[{"text":"Trigger","type":"text","marks":[{"type":"strong"}]},{"text":": User says \"bind domain\" / \"HTTPS\" / \"SSL\" after deployment exists.","type":"text"}]},{"type":"paragraph","content":[{"text":"See ","type":"text"},{"text":"reference/https/https_setup.md","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Key Constraints","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Constraint","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Rule","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Currency","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Always USD","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Auth","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"OAuth (recommended) or AK/SK; never collect credentials via chat","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Template upload","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Must use ","type":"text"},{"text":"--TemplateURL","type":"text","marks":[{"type":"code_inline"}]},{"text":" (WAF blocks TemplateBody)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Stack name retry","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Reuse — never regenerate","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Resource deletion","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Always via ","type":"text"},{"text":"delete_stack.sh","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Region default","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ap-southeast-1","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Commands to user","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Never show underlying commands","type":"text"}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"File Layout","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"scripts/\n generate_template.py upload_artifacts.py\n create_stack.sh record_state.py\n delete_stack.sh update_app.sh\n wait_and_probe.py setup_domain.sh\n append_timeline.py\nreference/\n deploy/\n 01_env_check.md ~ 14_app_timeline.md\n hotfix/\n update_app.md update_recipe.md\n cleanup/\n delete_stack.md\n https/\n https_setup.md\n rules/\n rule_interaction.md rule_error_handling.md ram_policies.md\ntemplates/\n ros_single[_rds].yaml\n userdata/{systemd,docker,nginx_proxy,nginx_static,nginx_static_proxy}.sh","type":"text"}]}]},"metadata":{"date":"2026-11-02","name":"qwencloud-deploy","skip":"Do NOT use when the user explicitly targets Aliyun China (aliyun.com), AWS, GCP, Azure, or another specific cloud platform.","input":"A local project directory, Git URL, or an existing deployment state file (.qwencloud-deploy). Optional: user preferences for instance type, region, database.","author":"@skillopedia","output":"A running cloud service with public IP (or domain + HTTPS), deployment state file (.qwencloud-deploy), and success card with access URL, cost summary, and next-step guidance.","source":{"stars":4,"repo_name":"qwencloud-deploy","origin_url":"https://github.com/QwenCloud/qwencloud-deploy/blob/HEAD/skills/deploy/SKILL.md","repo_owner":"QwenCloud","body_sha256":"def7b331942be0f519cfc95c6cca3e72967075ba325e0c0593d53313087d975b","cluster_key":"6a54d71255357b57154b6ea8bfaba72f62d090ea26e391552681e12f3a44513a","clean_bundle":{"format":"clean-skill-bundle-v1","source":"QwenCloud/qwencloud-deploy/skills/deploy/SKILL.md","text_bytes":231340,"source_commit":"6bc009a412a72e6b748b9b91d941d57420cb3813","skills_sh_rank":14978,"attachment_count":37,"text_attachments":37,"attachment_storage":"skill_attachments","binary_attachments":0},"cluster_size":1,"skill_md_path":"skills/deploy/SKILL.md","import_metadata":{"date":"2026-11-02","author":"@skillopedia","version":"2.2","category":"devops-infrastructure","category_label":"DevOps"},"exact_dupes_collapsed_into_this":0},"trigger":"Use when the user asks to deploy a project to the cloud, put an app online, publish a website, generate an access URL, deploy a Git repo, or update an online version — and has NOT specified a particular cloud platform. Also use when the user mentions \"Alibaba Cloud\", \"alibabacloud.com\", or the international site.","version":"2.2","category":"devops-infrastructure","import_tag":"skills-sh-top20k-2026-11","description":"One-click deploy, publish, and update a local project or Git repository to Alibaba Cloud International (alibabacloud.com), producing an accessible online service with a public IP. Supports full-stack ROS orchestration, automatic cloud-resource provisioning, pre-deployment price confirmation, service health checks, deployment-state recording, hot updates, and optional domain + HTTPS setup. Use when: the user asks to deploy a project to the cloud, put an app online, publish a website, generate an access URL, deploy a Git repo, or update an online version and has NOT named a specific cloud platform; or the user mentions \"Alibaba Cloud\", \"alibabacloud.com\", or the international site. Do not use when: the user explicitly targets Aliyun China (aliyun.com), AWS, GCP, Azure, or another specific cloud platform.","prerequisites":["aliyun CLI 3.x configured with international-site credentials in OAuth mode"]}},"renderedAt":1793661510548}

Qwen Cloud Deploy Quick Path 1. Route the task — Match to one of 4 modes: Full-Stack Deploy · Hot Update · Delete · HTTPS Setup. 2. Deploy (default) — Execute steps 1→14 strictly in order, no skipping/reordering; gates and skippable steps are in "Execution order". 3. Confirm cost before creating anything — Show hourly price in USD, get user confirmation. 4. Record state — On success write . Scope | In Scope | Out of Scope | |----------|--------------| | Local project / Git → Alibaba Cloud International | China site → use | | Full-stack ROS, hot update, cleanup | AWS/GCP/Azure/other clouds | |…