For AI agents: markdown of this page — /docs-content-en/infra/deploy/port.md documentation index — /llms.txt
Set the application port
PATCH /v1/infra/servers/:id/port
Sets the TCP port to which the tunnel agent proxies incoming HTTPS requests from the subdomain. By default the tunnel goes to :3000 — this is the platform standard, and most applications should listen on it. This endpoint is needed in rare cases: the application runs on a different port for historical reasons, or you want 0 (auto-detect) so the agent finds the listening port itself. Ports 1–1023 are forbidden — these are system ports (SSH, HTTP, HTTPS, SQL), and using them would create a risk of redirecting traffic to service processes.
Parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
id |
path | string (UUID) | yes | BLACKHOLE server ID, status: running, blackholeStatus: CONNECTED |
Request fields (body)
| Field | Type | Required | Description |
|---|---|---|---|
port |
number | yes | 0 (auto-detect) or 1024–65535. Ports 1–1023 are rejected with PORT_RESTRICTED |
Examples
curl — personal key
# Set port 8080
curl -X PATCH https://vibecode.bitrix24.com/v1/infra/servers/SERVER_ID/port \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"port": 8080}'
# Automatic detection
curl -X PATCH https://vibecode.bitrix24.com/v1/infra/servers/SERVER_ID/port \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"port": 0}'
curl — OAuth application
curl -X PATCH https://vibecode.bitrix24.com/v1/infra/servers/SERVER_ID/port \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{"port": 8080}'
JavaScript — personal key
const res = await fetch(
`https://vibecode.bitrix24.com/v1/infra/servers/${serverId}/port`,
{
method: 'PATCH',
headers: {
'X-Api-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({ port: 8080 }),
}
)
const { data } = await res.json()
console.log(`Application port: ${data.port}`)
JavaScript — OAuth application
await fetch(
`https://vibecode.bitrix24.com/v1/infra/servers/${serverId}/port`,
{
method: 'PATCH',
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({ port: 0 }),
}
)
Response fields
| Field | Type | Description |
|---|---|---|
success |
boolean | Always true on success |
data.port |
number | The final port. With port: 0 it returns 3000 (the default value on auto-detect) |
data.mode |
string | manual (a specific port was set) or auto (port: 0) |
data.verified |
boolean | true — the platform confirmed the agent proxies to this port (by probing the agent, and on a pinned server by reading the settings on the machine plus a probe after the restart). false — the port was saved but routing is not confirmed yet (see data.warning and "Known specifics") |
data.warning |
string | Present only when verified: false. Three states, each calling for a different action: the agent is still in auto-detect mode (the pin did not take — the scanner routes traffic), the agent accepted the port but the confirmation did not arrive (retry the request), or the port was written to a pinned server's settings but the agent has not confirmed the restart yet. In the first two cases /repair does not help and makes things worse; in the third it does the opposite and applies the saved port. The warning text says what to do |
data.pinned |
boolean | Whether the port is pinned in the agent settings on the machine. true — it survives a wake and a repair; false — it lives only in the agent's memory until the next restart |
Response example
{
"success": true,
"data": { "port": 8080, "mode": "manual", "verified": true, "pinned": true }
}
Error response example
409 — the agent rejected the port change:
{
"success": false,
"error": {
"code": "PORT_NOT_APPLIED",
"message": "The server agent runs in fixed-port mode and cannot change its port at runtime. Repair the server (POST /v1/infra/servers/:id/repair) to switch the agent to port auto-detection, then retry.",
"agentError": "NO_SCANNER"
}
}
Errors
| HTTP | Code | Description |
|---|---|---|
| 400 | VALIDATION_ERROR |
port is not an integer (fractional values are rejected), or is outside the 0–65535 range |
| 400 | PORT_RESTRICTED |
A port in the 1–1023 range (system ports) |
| 400 | GALAXY_APP_USE_GALAXY_ROUTE |
The server is a Galaxy app. Its container port is bound to the host and is set by the port field when you upload code — see Galaxy app |
| 401 | MISSING_API_KEY |
The X-Api-Key header was not provided |
| 401 | INVALID_API_KEY |
Invalid or expired API key |
| 403 | INFRA_FORBIDDEN_FOR_COWORK_KEY |
The call was made with a Cowork/Code key — such a key works with data only and cannot perform write operations. To issue a key that can, see Project key for deploy |
| 403 | SERVER_ROLE_FORBIDDEN |
You are on this server's development team with the Developer role, and this operation is open to the Administrator role. error.hint carries your role, the required threshold and the list of calls that are open to you. Role breakdown — List servers |
| 404 | NOT_FOUND |
The server is not BLACKHOLE + RUNNING, was deleted, or belongs to another API key while you are not on its development team |
| 409 | SERVER_NOT_READY |
The tunnel agent is not in the CONNECTED status |
| 409 | PORT_NOT_APPLIED |
The agent rejected the port change. agentError: NO_SCANNER — the server is in fixed-port mode (see below); a different agentError — the agent is outdated. Both are resolved by /repair. On a pinned server the same code arrives without agentError when nothing on the machine listens on the requested port: pinning it would leave the public URL dead, so the write is refused — the message lists the ports that are listening on the machine itself |
| 409 | SERVER_BUSY |
A deploy, an exec or another port change is already running on this server. Retry in a few seconds |
| 429 | RATE_LIMITED |
Rate limit exceeded: 10 requests per minute on this endpoint |
| 502 | AGENT_CONFIG_WRITE_FAILED |
Pinned servers only: the machine refused to write the agent settings. /repair is the fix — it reinstalls the agent together with its settings |
| 502 | GATEWAY_ERROR |
The Gateway could not deliver the command to the agent |
Full list of common API errors — Errors.
Known specifics
- System ports (1–1023) are forbidden for a reason. SSH (22), HTTP (80), HTTPS (443), DNS (53), PostgreSQL (5432), MySQL (3306) — opening a tunnel on them would create a risk of redirecting external traffic to service processes inside the virtual machine.
- How
port: 0works. The agent reads the machine's listening sockets from/proc/net/tcpand/proc/net/tcp6, probes each port with an HTTP request and points the tunnel at the one that answered. Among the ports that answered, it takes the lowest number, except80and443— those two are chosen only when nothing else answered. The restriction on system ports1–1023applies to setting the port explicitly with this call, and does not affect auto-detection. Five ports never take part in auto-detection:22,2375,2376,4243and9200. The machine's service interfaces answer on those ports, and publishing such an interface on the subdomain would open it to the internet. The filter applies to auto-detection only — the agent accepts any explicitly set port from the allowed range, so keep service interfaces out of the tunnel. Auto-detect suits applications that pick a port dynamically at startup. - Auto-detect also considers processes that listen on
127.0.0.1only. For a Black Hole application, that is the normal way to start: the agent reaches the application over the local interface, while the machine is closed from the outside. The consequence — a service process brought up on the machine only for local calls is indistinguishable from the application during auto-detection and can take the tunnel. When other processes that answer over HTTP run next to your application on the machine, set the application port explicitly with this call. Then the choice does not depend on who else is listening. - Auto-detect holds on to the previous port while something still answers on it. The scanner does not switch to a new port on a single observation: while a responding process is alive on the previous port, the tunnel target stays on it — so a brief stall of the application does not drop the tunnel onto a stub page. The practical consequence: if the application moved to another port and a live process stayed on the old one, auto-detection will not switch by itself. The way out is to set the port explicitly with this call, or to stop the process on the previous port. If the previous port simply became free, the switch happens on its own within about a minute. The hold does not apply to
80and443: when the target sits on one of them, auto-detection switches as soon as an application port answers. - A pinned port survives both a wake and a repair. The pin is stored on the machine itself — as the
local_httpline in the agent settings at/etc/vibe-agent/config.yml. The valueautomeans auto-detection, while a value such as127.0.0.1:8080means a fixed port. The platform writes that line. On a pinned server this call rewrites it. An unpinned server becomes pinned once the port is confirmed — by a successful deploy that passed its healthcheck, or by a confirmed port change through this call — if pinning is enabled for your Bitrix24 account. A pinned server answersportPinned: trueinGET /v1/infra/servers/:id, and once it is pinned both waking the server and/repairbring the agent back to the same port. On an UNPINNED regular server, repair sets auto-detection and the port is chosen again. For agents, bots and galaxy hosts, repair writes the fixed port from the database. port: 0is returned in the response as3000. This is not an error: "on auto-detect we return 3000 if nothing suitable was found". Check the actual listening port via/execwith the commandss -tlnp.- The platform confirms the port change (
data.verified). On an UNPINNED server, afterset_portthe platform probes the agent and checks that the tunnel actually proxies to the requested port.verified: true— routing is ready.verified: false+data.warning— the agent accepted the command but the confirmation did not arrive. Retry the request in a few seconds./repairis not the fix here and makes things worse: a port set by that command lives in the agent's memory, so the restart during a repair discards it and returns the agent to auto-detection.409 PORT_NOT_APPLIED— the agent did not accept the change at all: withagentError: NO_SCANNERthe server runs in fixed-port mode (run your application on the current port, or/repairto switch to auto-detection); with a differentagentErrorthe agent is outdated (/repairupdates it). - On a PINNED server this call works differently — but not right away. The port is applied by rewriting the agent settings and restarting the agent, and
verified: truemeans the settings carry the requested port and the agent is back online. The tunnel drops for a few seconds while that happens.port: 0removes the pin and returns the agent to auto-detection. If the agent did not make it back in time, the response carriesverified: false— that is not a failure: the port is already written and takes effect once the agent comes up. Distinct failures:502 AGENT_CONFIG_WRITE_FAILED— the machine refused to write the settings (run/repair),502 GATEWAY_ERROR— the command never reached the machine (retry later),409 PORT_NOT_APPLIEDwithoutagentError— nothing listens on the requested port. - The behavior above starts after the agent's first restart, not the moment
portPinned: trueappears. The path is chosen by the state of the MACHINE, not by the response field: until the agent has restarted, it still runs the scanner, and the call behaves as on an unpinned server — the tunnel does not drop, and409 PORT_NOT_APPLIEDwith anagentErrorcan arrive. A restart happens on a server wake, a deploy or a repair. So a handler written againstportPinnedmust be ready for both modes.