Use ucloud-sandbox-cli to operate on a site space the user has already created. The site space is backed by a sandbox; this skill is only responsible for connecting to and maintaining that site, not for creating sites or sandboxes.
Prerequisites and Platform
Before installing the CLI or calling the site API, first confirm that the current environment allows public network access. If network permission approval is required, request authorization first; if authorization is not granted, stop and explain why.
In a Windows or PowerShell environment, before installing, connecting, transferring files, or deploying, first read and follow the Windows PowerShell Guidein full. The Bash installation, credential injection, and local packaging commands on this page apply only to Linux and macOS; commands passed to sandbox exec are still executed in the remote Linux Shell.
Core Concepts
- The site connection Key format is
site_<sandbox-id>_<code>,<code>is a connection code randomly generated by the site space, used to prevent others from connecting to the site using only the sandbox ID. For example,site_iy1qen6gs2835o0udufdz_7f3a9c2ecorresponds to sandbox IDiy1qen6gs2835o0udufdz。 - The sandbox ID is the part after the
site_prefix and before the first_. The connection code is only a component of the Key; do not pass it to the CLI separately, and do not concatenate it into the sandbox ID. - The site connection Key is also a restricted API Key. Write the full Key into
UCLOUD_SANDBOX_API_KEY, but when passing a resource ID to the CLI, use only the derived sandbox ID. - The old format
site_<sandbox-id>(without_<code>) is no longer usable. When the user provides the old format, do not attempt to complete, guess, or omit the connection code, and do not switch to a regular API Key; directly ask the user to go to the StarMap console'sSite Space pageto copy the new site connection statement again. - Site credentials can only operate on the one sandbox they are bound to; they cannot list or delete sandboxes, nor operate on other resources such as templates.
/home/user/.site.envstores the environment variables the user configured for the website. It is managed by the site space; do not delete, overwrite, or include it in the deployment package.- The sandbox includes Python and Node.js by default; when truly needed, you can use
sandbox execto callaptto install other dependencies. - Sandbox commands run as the
useruser by default.userhas passwordless sudo configured; operations such as binding port 80 and other operations requiring root privileges should directly use non-interactivesudo -n, and do not first try running as a regular user.
Treat the site connection Key as a credential: do not repeatedly expose it (including the connection code within it) in replies, logs, generated code, or repository files, and do not write it into ~/.ucloud-sandbox-cli/config.json. Only set it temporarily in the shell environment where the CLI is executed. The derived sandbox ID does not contain the connection code and can appear normally in commands.
Permissions and Security Boundaries
Site operations use only the following capabilities:
sandbox exec: execute commands, inspect the environment, build projects, and manage services.sandbox host: obtain the site access address for port 80.fs ls、fs cat、fs mkdir、fs cp、fs mv、fs rm: manage files and directories within the site sandbox.
Do not attempt sandbox list、create、clone、kill、pause, and do not execute snapshots, templates, or other management commands. A site credential returning no permission does not mean the site connection failed.
Before performing file deletion, overwriting, or large-scale moves, first confirm that the path belongs to the current website and that the operation matches the user's intent. Do not delete /home/user、/home/user/.site.env or existing files of unknown origin just to "clean up the deployment directory".
Prepare and verify the CLI
The minimum supported version is v1.3.2。v1.3.1 , which starts making the control plane, RPC, files, and streaming requests uniformly inherit HTTP_PROXY、HTTPS_PROXY and NO_PROXY;v1.3.2 . It further requires the official installer to verify the Release SHA256. Earlier versions may falsely report DNS failures in restricted networks, or lack installation integrity verification.
First run ucloud-sandbox-cli versiononce. AstraFlow's local Agent PATH contains the real user's general CLI directory (on Linux/macOS it is ~/.local/bin), not each session's private $HOME, and not AstraFlow's Application Support directory. If the minimum version is already met, continue directly and do not update.
If the command does not exist or is lower than v1.3.2, only install the official installation command into the real user's ~/.local/bin. This step must be requested once as a complete command for host execution permission; after approval, do not separately request permissions for the installer's internal downloads, temporary directories, or file writes:
TMP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/ucloud-sandbox-cli.XXXXXXXX")" && \
trap 'rm -rf "$TMP_DIR"' EXIT && \
curl -fsSLo "$TMP_DIR/install.sh" \
https://raw.githubusercontent.com/ucloud/ucloud-sandbox-cli/main/install.sh && \
sh "$TMP_DIR/install.sh" -y -p "$HOME/.local/bin" && \
"$HOME/.local/bin/ucloud-sandbox-cli" version
Do not try /usr/local/binfirst, do not use sudo, do not install into the Agent session's private $HOME, do not write or hardcode AstraFlow's sandbox-workspaces / Application Support path, and do not use find $HOME to search for the CLI. After installation is complete, return to the Default sandbox and use it by command name ucloud-sandbox-cli ; the real user directory is reused across sessions and restarts.
On Windows, follow the Windows PowerShell guide to use a user-level installation directory; likewise combine installation and version verification into a single approved host command.
Only when the user explicitly requests updating the CLI, if the installed version is v1.3.4 or higher, directly use the built-in update command, and there is no need to re-download the installation script. There is no interactive terminal here, so you must include -y to skip confirmation:
ucloud-sandbox-cli update -y && ucloud-sandbox-cli version
update will verify the Release SHA256 and then replace the current program, keeping the original installation directory unchanged. Versions lower than v1.3.4 do not have this command; reinstall according to the installation process above. When querying the version reports GitHub API rate limiting, explain the reason and have the user retry later or set GITHUB_TOKEN。
This section only prepares ucloud-sandbox-cli; do not install or update this Skill itself.
Determine whether the Skill is up to date
When you need to confirm whether the Skill is the latest version, compare the installed CLI version with the latest GitHub release; if the two match (or the Skill-related files have no lagging commits), the Skill is considered up to date:
ucloud-sandbox-cli version
curl -fsSL https://api.github.com/repos/ucloud/ucloud-sandbox-cli/releases/latest | grep tag_name
If it is not the latest, vianpx skills add ucloud/ucloud-sandbox-cli -s astraflow-api -s ucloud-sandbox-siteprompt the user to update the skill
Connect to the site
1. Obtain and verify the site connection Key
If the user has not yet provided a site connection Key, only ask the user for site_<sandbox-id>_<code> format connection Key (that is, the site connection statement on the site space page); do not ask for an ordinary UCloud API Key, and do not ask only for the sandbox ID. First complete the CLI installation and verification according to the previous section.
On Linux and macOS, verify the Key, set credentials, and derive the sandbox ID in the same shell invocation:
SITE_KEY='site_<sandbox-id>_<code>'
case "$SITE_KEY" in
site_*_*) ;;
site_?*)
echo "检测到旧版站点 ID 格式 site_<sandbox-id>,已不再支持。请到星图控制台的站点空间页面重新获取站点连接语句(site_<sandbox-id>_<code>)。" >&2
exit 1 ;;
*)
echo "站点连接 Key 格式无效,应为 site_<sandbox-id>_<code>" >&2
exit 1 ;;
esac
SITE_BODY="${SITE_KEY#site_}"
SANDBOX_ID="${SITE_BODY%%_*}"
SITE_CODE="${SITE_BODY#*_}"
if [ -z "$SANDBOX_ID" ] || [ -z "$SITE_CODE" ]; then
echo "站点连接 Key 缺少沙箱 ID 或连接码,请到星图控制台的站点空间页面重新获取站点连接语句。" >&2
exit 1
fi
export UCLOUD_SANDBOX_API_KEY="$SITE_KEY"
SANDBOX_ID only take the part before the first _ , and keep the connection code in UCLOUD_SANDBOX_API_KEY ; do not put SITE_CODE or pass the complete Key to the resource ID parameter of any CLI subcommand.
When validation fails, stop immediately and do not continue trying sandbox exec. When the user provides an old format, only reply that the connection statement needs to be obtained again from the site space page; do not output any speculative values other than the old ID given by the user.
Environment variables are only effective for the current shell process and its child processes. Each time the Agent starts a new shell invocation, it must re-inject UCLOUD_SANDBOX_API_KEY and derive SANDBOX_ID; do not assume that the previous export is still effective.
The site's region or API domain is still determined by the existing CLI configuration and UCLOUD_SANDBOX_REGION、UCLOUD_SANDBOX_DOMAIN . Do not switch arbitrarily without evidence; if the connection fails and the region is suspected to be incorrect, confirm the site region with the user.
2. Verify the connection and check the initial directory in a single invocation
ucloud-sandbox-cli sandbox exec "$SANDBOX_ID" \
"printf 'SITE_CONNECTED\\n'; pwd; printf 'SITE_HOME\\n'; ls -la /home/user"
As long as this exec succeeds, consider that the AI has connected to the site and completed the initial directory check, and can continue generating code and deploying. Do not split connection verification,pwd , and the initial ls into multiple invocations, and do not use sandbox list to verify the connection.
3. Identify site access code protection
CLI connection verification and public URL access are two different things: the AI can connect to the sandbox via the CLI, but a public site configured with an access code cannot be directly verified by the AI.
When accessing sandbox host or a user-defined domain, use a request that carries no access code to check the HTTP status and response body. If it returns 401 and the response body contains Site protected, determine that the site has access code protection enabled, rather than a service failure. Do not guess, bypass, or retry the access code, and do not ask the customer to send the access code to the AI; the access code is sensitive content and must not be written into commands, logs, code, or replies.
At this point, the verification result of http://127.0.0.1:80 within the site may be retained, but public page verification must be handed over to the customer: give the address returned by sandbox host to the customer, and let the customer enter the access code themselves in the browser. Explain to the customer that the AI cannot complete public page verification when the access code is enabled.
If the customer really needs the AI to verify the public page during the development phase, ask the customer to temporarily disable the access code in the site space console first, complete the verification, and then re-enable it. For configuration methods, refer tosite space documentation. Even if the customer proactively provides the access code, do not let the AI use or save the access code on their behalf.
4. Identify public access denied (403)
A public URL returning 403 indicates that the site gateway rejected this access; it is not a website service failure, nor a CLI connection failure. Before determining, read the response body first, and handle it according to the following three cases; do not retry, bypass, or change the egress IP:
| Response body characteristic | Cause | Handling |
|---|---|---|
Contains This site does not accept requests from your IP address |
The access source IP is not allowed | Ask the customer to check the site's IP whitelist and blacklist configuration on the site space page of the Xingtu console, and confirm whether the current access source is allowed |
Contains Domain not allowed |
The site is configured with a custom domain and only allows access through that domain | The CLI cannot obtain the custom domain configured for the site; the AI must not guess or concatenate the domain. Hand over public page verification to the customer, and ask the customer to access it using the custom domain they configured in the Xingtu console |
Contains Port not allowed |
Accessed a port other than 80 | The site only exposes port 80. Switch back to accessing via port 80, and confirm the service is listening on 0.0.0.0:80, and do not deliver externally through other ports |
Both the IP allowlist and custom domain are site-side configurations. The AI cannot query or modify them via the CLI, and can only guide the customer to adjust them in the Xingtu console or switch to accessing via a custom domain. In this case, you may retain the verification result for http://127.0.0.1:80 within the site, but do not announce that the public page verification has passed.
5. Return the unified connection prompt
After completing connection verification (whether successful or failed), return the prompt to the user according to the fixed template in this section. Do not omit fields, change the wording, or substitute another format; in the template, <sandbox-id>、<region> should be replaced with actual values.
When the connection is successful (the exec verification in step 2 passes), return:
已成功连接站点,可以开始开发。
- 沙箱 ID:<sandbox-id>
- 地域:<region>
- 工作目录:/home/user
- 连接技能:ucloud-sandbox-site(<技能状态>)
使用指引
- 开发站点:用自然语言描述你的想法,Agent 会帮你开发。
- 保存数据:站点已预装 PostgreSQL,默认未启动。需要时告诉 Agent:“使用预装数据库保存数据。”
- 查看效果:开发完成后,回到「站点空间」,点击「访问」即可查看,无需单独发布。
When the connection fails (the connection Key verification passes but the exec verification fails), return:
连接失败,暂时无法访问站点。
- 沙箱 ID:<sandbox-id>
- 地域:<region>
- 失败原因:<根据实际返回信息填写>
- 连接技能:ucloud-sandbox-site(<技能状态>)
排查指引
- 更新技能:旧版技能可能导致连接失败,请重新安装最新版后重试。
- 核对连接信息:回到「站点空间」,重新复制完整连接语句后交给 Agent。
- 仍无法连接:将以上信息及错误提示提供给技术支持,协助排查。
Sources of each field:
- Sandbox ID: the sandbox ID derived from the connection Key, excluding the connection code.
- Region: the region in the current CLI configuration or
UCLOUD_SANDBOX_REGION, which can be confirmed viaucloud-sandbox-cli config. - Working directory: the output of
pwdin the verification command in step 2, normally/home/user。 - Failure reason: excerpted from the CLI's actual error output. It may be summarized but must not be fabricated, and must not include the full connection Key or connection code.
- Connection skill status, choose one of three: when the session or platform has confirmed that the skill is the latest version, use "Already up to date"; when it has been confirmed that the skill is not the latest version, use "Please reinstall the latest version, otherwise new features may be affected" (success template) or "Please reinstall the latest version, otherwise the connection and new features may be affected" (failure template); when the check cannot be completed, use "Unable to check for updates, please confirm whether it is the latest version". Do not fabricate check results.
When the connection Key is in an old format or fails verification, do not apply the failure template; reply according to the requirements of "Obtain and verify the site connection Key". After a successful connection, when continuing to perform site operations, there is no need to repeatedly return the success template.
Common commands
The following examples all assume that the current shell has correctly set UCLOUD_SANDBOX_API_KEY and SANDBOX_ID。sandbox can be abbreviated as sbx。
Execute a command
The command content must be passed as a single complete string to exec:
ucloud-sandbox-cli sandbox exec "$SANDBOX_ID" "pwd && ls -la /home/user"
ucloud-sandbox-cli sandbox exec "$SANDBOX_ID" "python3 --version && node --version && npm --version"
Do not use sudo for ordinary project operations, including uploading or modifying code under /home/user , installing project dependencies, running builds, and reading .site.env. Otherwise, root-owned project files will be created, hindering subsequent updates.
The following operations usually require root privileges; use sudo -n:
- on first execution: listening on privileged ports below 1024 such as port 80, and stopping service processes started by root.
- Use
apt-getto install system dependencies. - Use
systemctl、serviceor modify system-level service configurations. - Write to system directories such as
/etc、/usr、/usr/local、/var, or adjust the permissions and ownership of files that do not belong touser.
Do not use sudo locally for the entire ucloud-sandbox-cli command; only elevate the parts that are truly needed in the remote command passed to sandbox exec . Do not use interactive sudo. When privilege escalation is needed, first use sudo -n true to verify passwordless privileges; if it fails, report the problem and do not wait for password input.
Install only when the project truly requires additional system packages:
ucloud-sandbox-cli sandbox exec "$SANDBOX_ID" "sudo -n apt-get update && sudo -n apt-get install -y <package>"
PostgreSQL 15 and pgvector (only applicable to the site template)
Built on the site series template (the specification template naming format is site-{CPU核数}c-{内存GiB数}g) the site has PostgreSQL 15, the client, and pgvector built in. First check the actual environment; do not judge whether the database is installed or started based only on the site connection Key:
ucloud-sandbox-cli sandbox exec "$SANDBOX_ID" \
"whoami && command -v start-postgres && command -v stop-postgres && psql --version"
The default Linux user should be user。base The template does not include these database components; if the commands are missing, first confirm the site template and actual installation status, and do not use site credentials to create or replace the sandbox.
Start, verify, and stop
start-postgresinternally executessudo -n systemctl start postgresql-vector.service, and its dependencies startpostgresql@15-main.service, so callers do not need to wrap it in another layer of sudo.postgresql-vector.serviceis a oneshot initialization unit running aspostgres: throughenable-pgvectorit creates the non-superuser roleuseron demand, theuclouddatabase owned by that role, and executes inucloudExecute inCREATE EXTENSION IF NOT EXISTS vector。- The initialization unit uses
RemainAfterExit=yes, showingactive (exited)as normal; repeatedly starting an already active unit will not re-execute the initialization SQL, nor will it correct the attributes of an existing role or database.
Start the database in the same sandbox:
ucloud-sandbox-cli sandbox exec "$SANDBOX_ID" "start-postgres"
Check the service, connection identity, and vector type through the Unix Socket.pg_isready can only check that the service is ready; only subsequent successful SQL proves that the application identity can connect and use pgvector:
ucloud-sandbox-cli sandbox exec "$SANDBOX_ID" \
"sudo -n systemctl is-active postgresql@15-main.service && \
sudo -n systemctl is-active postgresql-vector.service && \
pg_isready -h /var/run/postgresql -p 5432 -U user -d ucloud && \
psql -X -w -v ON_ERROR_STOP=1 -h /var/run/postgresql -p 5432 -U user -d ucloud \
-c \"SELECT current_user, current_database(), '[1,2,3]'::vector;\""
The expected query returns user、ucloud and [1,2,3]. When you need to stop the database, execute:
ucloud-sandbox-cli sandbox exec "$SANDBOX_ID" "stop-postgres"
stop-postgres internally stops postgresql@15-main.service, and the initialization unit stops along with the dependency relationship; it does not delete the database. Do not make stopping the database the final step of connection verification, so as not to interrupt the website.
Application connection configuration
The template uses the local Unix Socket directory by default /var/run/postgresql, port 5432, database ucloud , and role user。pg_hba.conf For local Sockets, use peer authentication, and for all TCP connections over IPv4 and IPv6 (including loopback addresses), use reject; the template also disables PostgreSQL SSL.
- Application and migration commands must be run inside the same sandbox as Linux user
user. peer checks the operating system identity; merely filling in the database username in the configurationuserdoes not allow a root process to pass authentication. - Explicitly specify the Socket directory; do not use
127.0.0.1orlocalhost. Do not assume that omittinghostwill use the Socket; for example, Node.js'spgconnects tolocalhost。 - by default. After specifying the Socket directory,
port=5432selects the.s.PGSQL.5432Socket file, which does not mean it uses TCP. This connection does not require a database password, and you should not require SSL or openpg_hba.confto fix the connection. - Do not use the superuser
postgresto run business applications; usesudo -n -u postgres psql。
for necessary administrative operations. Application connection example:
| Client | Connection example |
|---|---|
| Python / psycopg | psycopg.connect("host=/var/run/postgresql port=5432 dbname=ucloud user=user") |
| Node.js / pg | new Pool({ host: '/var/run/postgresql', port: 5432, database: 'ucloud', user: 'user' }) |
| Go / pgx or lib/pq | host=/var/run/postgresql port=5432 dbname=ucloud user=user sslmode=disable |
Satisfies both peer authentication and the port 80 requirement
Dynamic websites that use a database cannot apply the root static service startup example later in this document. Through systemd's User=user and AmbientCapabilities=CAP_NET_BIND_SERVICE , the application can, as user , bind 0.0.0.0:80, using sudo -n manage the service. In this case, the process, PID, and logs are managed by systemd, so there is no need to store a separate PID file; environment variable loading and HTTP verification are still performed as described in the deployment chapter.
Database troubleshooting
| Symptom | Handling |
|---|---|
| Socket does not exist or connection refused | Check start-postgres result,systemctl status postgresql@15-main.service postgresql-vector.service and /var/run/postgresql; when logs are needed, use sudo -n journalctl -u postgresql@15-main.service -u postgresql-vector.service -n 100 --no-pager, and check whether they contain sensitive content before outputting |
pg_hba.conf rejects connection, or the logs show 127.0.0.1 / ::1 |
the client used TCP; explicitly change host to the Socket directory, and check whether environment variables or the connection URL override the configuration |
Peer authentication failed or role "root" does not exist |
Check the Linux user and database role of the actual application or migration process, and change them to user; do not bypass peer through trust, passwords, or enabling TCP |
Missing ucloud、user or vector type |
Check the initialization unit status and logs, and confirm that you are connecting to ucloud; the initialization script only enables vector |
Browse and read files
ucloud-sandbox-cli fs ls "$SANDBOX_ID" /home/user
ucloud-sandbox-cli fs ls "$SANDBOX_ID" /home/user --format json
ucloud-sandbox-cli fs cat "$SANDBOX_ID" /home/user/site/index.html
Only use fs caton ordinary files confirmed not to contain sensitive information. Do not use /home/user/.site.env on fs cat。
Create directory
ucloud-sandbox-cli fs mkdir "$SANDBOX_ID" /home/user/site
The command still succeeds when the directory already exists, and prompts Directory already exists. When creating multiple directory levels, call fs mkdirlevel by level starting from the existing parent directory; if you need to create the entire directory tree at once, you can use sandbox exec to execute a validated mkdir -p。
Upload and download files
fs cp The remote endpoint format of <sandbox-id>:<path>is
# 上传
ucloud-sandbox-cli fs cp ./index.html "$SANDBOX_ID:/home/user/site/index.html"
# 下载
ucloud-sandbox-cli fs cp "$SANDBOX_ID:/home/user/site/service.log" ./service.log
, and exactly one of the source and target must be a remote endpoint. It copies only one file at a time: .envWhen uploading a directory, first package it locally, then upload it and extract it on the site. Exclude
LOCAL_PROJECT_DIR='./site'
tar \
--exclude='.git' \
--exclude='.env' \
--exclude='.env.*' \
--exclude='node_modules' \
-czf /tmp/site-release.tgz -C "$LOCAL_PROJECT_DIR" .
ucloud-sandbox-cli fs cp /tmp/site-release.tgz "$SANDBOX_ID:/tmp/site-release.tgz"
ucloud-sandbox-cli sandbox exec "$SANDBOX_ID" \
"mkdir -p /home/user/site && tar -xzf /tmp/site-release.tgz -C /home/user/site && rm -f /tmp/site-release.tgz"
, credentials, dependency directories, and other local files that should not be deployed:
Move and delete files
ucloud-sandbox-cli fs mv "$SANDBOX_ID" /home/user/site/old.html /home/user/site/index.html
ucloud-sandbox-cli fs rm "$SANDBOX_ID" /home/user/site/obsolete.html
fs rm is a destructive operation. Confirm the exact path before executing; when you need to delete a directory or batch files, do not concatenate unvalidated user input into rm -rf。
Safely read site environment variables
When the user asks about configured environment variables, you can tell them whether the variable exists and display non-sensitive variables. If the variable name contains API_KEY or KEYcase-insensitively, you must never output its value; only state that the variable exists or display <已隐藏>。
Do not directly run the following commands that may leak credentials:
fs cat ... /home/user/.site.envcat /home/user/.site.env- Unfiltered
env、printenv、setorexport -p - Enable when loading environment variables
set -x
When you need to view a configuration summary, parse and redact it line by line inside the sandbox:
ucloud-sandbox-cli sandbox exec "$SANDBOX_ID" 'awk '\''
/^[[:space:]]*(#|$)/ { next }
{
line=$0
sub(/^[[:space:]]*export[[:space:]]+/, "", line)
eq=index(line, "=")
if (!eq) next
name=substr(line, 1, eq-1)
gsub(/^[[:space:]]+|[[:space:]]+$/, "", name)
if (name !~ /^[A-Za-z_][A-Za-z0-9_]*$/) next
if (toupper(name) ~ /API_KEY|KEY/) print name "=<已隐藏>"
else print line
}
'\'' /home/user/.site.env'
If you only need to confirm whether a sensitive variable exists, verify that the variable name is a valid shell identifier, then return only "exists" or "does not exist"; do not return the value. If .site.env does not exist, report the fact and ask the user; do not create an empty file yourself to replace it.
When building or starting the user's website, load all variables through the following pattern without printing the contents:
set -a
source /home/user/.site.env
set +a
Generate and deploy websites
Choose an appropriate frontend technology stack based on user requirements. First review the existing files and project configuration, then generate or modify code locally and upload it; do not replace the user's existing framework without cause. When deploying, comply with the following hard requirements:
- The service must listen on
0.0.0.0:80, not only on127.0.0.1, and must not be delivered on ports such as 3000, 5173, 8080, etc. The default user in the sandbox isuserwhen binding to port 80, you must use it from the very first startupsudo -n。 - both when building and when starting the service
source /home/user/.site.env; the loading process must not output variable contents. - The service must run persistently detached from
sandbox exec. Usenohupor the service manager already present in the site, and redirect standard input, standard output, and standard error. - Save the PID and logs. Liveness checks and stopping of the root service must also use
sudo -n killwhen restarting, only terminate the old PID you recorded yourself; do not use broad commands such aspkill node、killallthat affect other processes. - Only after accessing within the site
http://127.0.0.1:80successfully, callsandbox hostand announce deployment success to the user.
Build example
For Node projects, build according to the project's own lockfile and scripts; the following is only a common pattern:
ucloud-sandbox-cli sandbox exec "$SANDBOX_ID" \
"cd /home/user/site && set -a && source /home/user/.site.env && set +a && npm ci && npm run build"
If there is no package-lock.json, choose the command according to the project's actual package manager and lockfile; do not mechanically run npm ci。
Do not use sudo to run npm、pnpm、yarn or build scripts; only elevate privileges when starting the final port 80 service.
Persistent startup example
For a purely static website whose build output is located in /home/user/site/dist , you can use the already installed Python to run it persistently:
ucloud-sandbox-cli sandbox exec "$SANDBOX_ID" '
set -e
PID_FILE=/home/user/site/service.pid
LOG_FILE=/home/user/site/service.log
sudo -n true
if [ -s "$PID_FILE" ]; then
old_pid=$(cat "$PID_FILE")
if sudo -n kill -0 "$old_pid" 2>/dev/null; then
sudo -n kill "$old_pid"
fi
fi
sudo -n touch "$PID_FILE" "$LOG_FILE"
sudo -n chown user:user "$PID_FILE" "$LOG_FILE"
sudo -n bash -lc "
set -e
set -a
source /home/user/.site.env
set +a
nohup python3 -m http.server 80 --bind 0.0.0.0 --directory /home/user/site/dist \
>/home/user/site/service.log 2>&1 </dev/null &
echo \$! >/home/user/site/service.pid
"
'
Before startup, create the log and PID files via sudo, then return ownership to user, which is compatible with root files left over from previous trial and error and also avoids requiring constant privilege escalation for future maintenance. The PID must be recorded inside the root launcher $!, ensuring the PID points to the actual website service, not the outer sudo wrapper process.
For SSR, Node, or other dynamic services that do not use a local PostgreSQL, retain the same sudo -n, PID, logging, background running, and environment variable loading pattern, replace exec python3 ... with the project's production startup command, and explicitly set or pass in HOST=0.0.0.0、PORT=80. Do not treat the development server as the default production deployment solution.
Verify and return the address
ucloud-sandbox-cli sandbox exec "$SANDBOX_ID" \
"curl -fsS --max-time 10 http://127.0.0.1:80/ >/dev/null && echo SITE_HTTP_OK"
ucloud-sandbox-cli sandbox host "$SANDBOX_ID" 80
Tell the user the actual address output by the sandbox host exactly as it is; do not guess or concatenate a domain name. At the same time, briefly explain what was deployed, the listening port, and the verification result. sandbox host Tell the user the actual address output exactly as it is; do not guess or concatenate a domain name. At the same time, briefly explain what was deployed, the listening port, and the verification result.
When verifying a public URL, read both the HTTP status code and the response body; first distinguish gateway rejection from service failure, then decide whether to investigate the service:
401and the response body containsSite protected: access code protection, handle according to "identify site access code protection".403: access is denied by the gateway; according to "identify public access denied (403)", compare the response body to determine whether it is an IP allowlist, custom domain, or port restriction.
Neither of these two cases indicates an abnormality in the website service, nor do they affect the HTTP verification result within the site, but neither can be used to declare public page verification successful. If verification fails and it does not fall into the above two categories, first check the process, port 80, and service logs:
ucloud-sandbox-cli sandbox exec "$SANDBOX_ID" \
'if [ -f /home/user/site/service.pid ]; then pid=$(cat /home/user/site/service.pid); sudo -n ps -p "$pid" -o pid=,stat=,cmd=; fi; sudo -n ss -ltnp | grep '\'':80'\'' || true; tail -n 100 /home/user/site/service.log'
The example above wraps the remote command in single quotes, so that $() is expanded in the sandbox. When rewriting the command or changing the quoting level, do not let the local shell execute the remote expression in advance.
Troubleshooting
| Symptoms | Resolution |
|---|---|
The user provided the old format site_<sandbox-id> |
Do not attempt to connect or complete the connection code; inform the user that the format has been updated and ask them to re-copy the site connection statement from the site space page in the StarMap console |
exec An error indicating no permission or authentication failure is shown |
Confirm that the complete site_<sandbox-id>_<code> is used as the API Key (the connection code is not truncated), and the derived sandbox ID is used as the resource ID; if it still fails, ask the user to confirm whether the connection statement has been regenerated in the console; do not switch to sandbox list for testing |
| An error indicating that the sandbox cannot be found is shown | Check whether the complete connection Key or a string containing the connection code is mistakenly used as the sandbox ID; the sandbox ID only takes the part before the first _ , and confirm the site region with the user |
.site.env does not exist |
Report the missing item and ask the user; do not create it on your own or overwrite it with a local .env Override |
An error is reported when starting port 80 Permission denied |
Confirm that the startup command uses sudo -nfrom the very first execution; do not first try to bind port 80 as a regular user |
sudo It waits for a password or prompts that a terminal is required |
Switch to sudo -n; if sudo -n true fails, report an abnormal passwordless sudo configuration and do not attempt to enter a password |
exec It does not return after starting the service |
Confirm that the service is already running in the background and redirect stdin, stdout, and stderr all together |
| Accessing port 80 within the site fails | Check the PID, logs, startup command, and listening address, and confirm that the service is listening on 0.0.0.0:80 |
The public URL returns 401 and the response body contains Site protected |
This is access code protection, not a service failure; do not request or use the access code, and let the customer enter it for verification themselves; if AI verification is needed, first have the customer temporarily disable the access code |
The public URL returns 403 and the response body contains This site does not accept requests from your IP address |
The access source IP is rejected; ask the customer to check the site's IP whitelist and blacklist configuration on the site space page in the StarMap console; do not retry or change the egress IP |
The public URL returns 403 and the response body contains Domain not allowed |
The site is configured with a custom domain and can only be accessed through that domain; the CLI cannot obtain that domain, so do not guess or concatenate it; ask the customer to access and verify using the custom domain they configured |
The public URL returns 403 and the response body contains Port not allowed |
The site only opens port 80; switch back to accessing via port 80 and confirm that the service is listening on 0.0.0.0:80 |
sandbox host There is output but the page cannot be opened |
Do not declare success based on this; first verify within the site using curl , then check the process and logs |
CLI is lower than v1.3.2 and a DNS/proxy error occurs |
According to "Prepare and Verify the CLI", request the host installation command only once, upgrade the CLI to the real user directory; return to the Default sandbox and retry once, and do not switch to the host to execute site commands |
CLI is already v1.3.2 or higher but a DNS/proxy error still occurs |
Keep the Default sandbox; if the platform requires it, request network authorization for the current session only once and retry once. If it still fails, report the domain, port, and original error; do not continue requesting host execution permissions. |