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

Terminal
# 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

Terminal
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

javascript
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

javascript
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

JSON
{
  "success": true,
  "data": { "port": 8080, "mode": "manual", "verified": true, "pinned": true }
}

Error response example

409 — the agent rejected the port change:

JSON
{
  "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: 0 works. The agent reads the machine's listening sockets from /proc/net/tcp and /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, except 80 and 443 — those two are chosen only when nothing else answered. The restriction on system ports 1–1023 applies 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, 4243 and 9200. 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.1 only. 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 80 and 443: 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_http line in the agent settings at /etc/vibe-agent/config.yml. The value auto means auto-detection, while a value such as 127.0.0.1:8080 means 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 answers portPinned: true in GET /v1/infra/servers/:id, and once it is pinned both waking the server and /repair bring 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: 0 is returned in the response as 3000. This is not an error: "on auto-detect we return 3000 if nothing suitable was found". Check the actual listening port via /exec with the command ss -tlnp.
  • The platform confirms the port change (data.verified). On an UNPINNED server, after set_port the 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. /repair is 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: with agentError: NO_SCANNER the server runs in fixed-port mode (run your application on the current port, or /repair to switch to auto-detection); with a different agentError the agent is outdated (/repair updates 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: true means the settings carry the requested port and the agent is back online. The tunnel drops for a few seconds while that happens. port: 0 removes the pin and returns the agent to auto-detection. If the agent did not make it back in time, the response carries verified: 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_APPLIED without agentError — nothing listens on the requested port.
  • The behavior above starts after the agent's first restart, not the moment portPinned: true appears. 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, and 409 PORT_NOT_APPLIED with an agentError can arrive. A restart happens on a server wake, a deploy or a repair. So a handler written against portPinned must be ready for both modes.

See also