Skip to content

Inbounds ​

An inbound is one VPN service: an OpenVPN, OpenConnect or WireGuard listener on a node. The API calls it instances. An inbound with nodeId: -1 is not assigned yet; 0 is the panel's own server. A multi-node inbound has one deployment per node.

These endpoints list and change inbounds, read their defaults and access, deploy them, override settings per node, start and stop them, and read their logs. Traffic is bytes and times are Unix seconds.

Brief list ​

GET/api/instances/briefpermissioninbounds.view

Returns inbounds with names, states and addresses only. Add ?deployments=1 to include the per-node deployments of a multi-node inbound.

bash
curl -sS -H "Authorization: Bearer $OVIRA_TOKEN" "$BASE/instances/brief?deployments=1"
json
[
  {
    "id": 12,
    "technicalName": "udp1194",
    "nodeId": 0,
    "node": "this server",
    "name": "udp1194",
    "proto": "udp",
    "port": 1194,
    "enabled": true,
    "authMode": "cert",
    "description": "",
    "network": "10.128.0.0/16",
    "staticStart": "10.128.255.0",
    "staticEnd": "10.128.255.255",
    "kind": "openvpn"
  }
]

List inbounds ​

GET/api/instancespermissioninbounds.view

Requires inbounds.view: all. Accounts with own scope must use GET instances/brief. Returns inbounds with their full settings, link state, address pool, client count and deployments. Add ?deployments=1 for per-node deployments.

bash
curl -sS -H "Authorization: Bearer $OVIRA_TOKEN" "$BASE/instances?deployments=1"
json
{
  "items": [
    {
      "id": 12,
      "kind": "openvpn",
      "nodeId": 0,
      "name": "udp1194",
      "enabled": true,
      "proto": "udp",
      "port": 1194,
      "network": "10.128.0.0/16",
      "active": true,
      "state": "active",
      "link": { "connected": true, "online": 3 },
      "clients": 42,
      "settings": { "authMode": "cert", "tlsMode": "tls-crypt" }
    }
  ],
  "system": "Ubuntu",
  "openvpn": "2.6.12",
  "publicHost": "panel.example.com"
}

Create an inbound ​

POST/api/instancespermissioninbounds.manage

Returns 201 with the new inbound, and a warning when part of the change did not apply. Assigning a node is normally a separate call; nodeIds deploys right after creation.

FieldTypeRequiredMeaning
displayNamestringnoName shown instead of name, when set.
kindstringnoopenvpn, ocserv or wireguard. Empty means openvpn. Fixed after creation.
nodeIdintegernoIgnored on create. New inbounds start unassigned (-1); use nodeIds to deploy.
namestringyesInbound name and service name. Unique.
enabledbooleannoTrue to switch it on.
protostringyesudp, tcp, udp6 or tcp6.
portintegeryesPort to listen on.
networkstringyesTunnel network in CIDR form.
settingsobjectnoProtocol settings. See below.
accessGroupsinteger[]noGroups that may use the inbound. Absent grants every group.
ownListClientsbooleannoTrue to let clients pick this inbound directly. Absent means true.
nodeIdsinteger[]noNodes to deploy to right after creation.
portsobjectnoPort per deployment node, keyed by node id.
bash
curl -sS -H "Authorization: Bearer $OVIRA_TOKEN" \
  -H "Content-Type: application/json" -X POST "$BASE/instances" \
  -d '{
    "kind": "openvpn",
    "name": "udp1194",
    "enabled": true,
    "proto": "udp",
    "port": 1194,
    "network": "10.128.0.0/16",
    "settings": {
      "authMode": "cert",
      "tlsMode": "tls-crypt",
      "dns": ["1.1.1.1"],
      "redirectGateway": true,
      "maxClients": 0
    },
    "accessGroups": [3]
  }'
json
{
  "instance": {
    "id": 12,
    "kind": "openvpn",
    "nodeId": -1,
    "name": "udp1194",
    "enabled": true,
    "proto": "udp",
    "port": 1194,
    "network": "10.128.0.0/16",
    "active": false,
    "state": "inactive",
    "clients": 0
  }
}

400 names the bad field, including a used port or an overlapping tunnel network. 402 means the licence does not allow another inbound.

Settings object ​

Every field is optional; the panel fills the ones you leave out with its defaults. Send back the object you read from GET instances/defaults or GET instances/{id} after editing.

FieldTypeMeaning
authModestringcert, cert+pass or pass: how clients prove themselves.
tlsModestringtls-crypt, tls-auth or none: control-channel protection.
dataCiphersstring[]Negotiated AEAD ciphers.
fallbackCipherstringCipher for pre-2.4 clients; empty means none.
authDigeststringHMAC digest.
tlsMinVersionstring1.2 or 1.3.
dnsstring[]Resolvers pushed to clients.
searchDomainstringDOMAIN pushed to clients.
redirectGatewaybooleanSend every packet through the tunnel.
blockOutsideDnsbooleanBlock DNS outside the tunnel (Windows leak fix).
pushRoutesstring[]CIDRs routed through the tunnel.
ipv6booleanOffer tunnel addresses from network6.
network6stringIPv6 tunnel network in CIDR form.
clientToClientbooleanLet clients reach each other.
maxClientsintegerConcurrent client cap; 0 means none.
keepaliveIntervalintegerKeepalive interval in seconds.
keepaliveTimeoutintegerKeepalive timeout in seconds.
tunMtuintegerTunnel MTU; 0 means the default.
mssFixintegerMSS clamping value; 0 means off.
fragmentintegerUDP fragment size; 0 means off.
sndRcvBufintegerSocket buffer size; 0 means the system default.
compressionstringoff, lz4-v2 or lzo.
renegSecintegerKey renegotiation interval in seconds.
portSharestringHost port to share with another service; TCP only.
exitNotifybooleanTell clients when the server stops.
multihomebooleanAnswer UDP from the address the packet arrived on.
remotesobject[]Client addresses: label, host, port. Empty uses the node's addresses.
remotestringThe first of remotes, kept for older versions.
verbintegerLog verbosity, 0-11.
natbooleanKeep a NAT rule for the tunnel network.
serverCustomstringExtra server configuration lines, checked against a denylist.
clientCustomstringExtra client configuration lines, checked against a denylist.
descriptionstringText shown with the inbound's profiles.
ocobjectOpenConnect settings.
wgobjectWireGuard settings.

OpenConnect settings (oc) ​

FieldTypeMeaning
dtlsbooleanAlso listen on UDP on the same port.
camouflagebooleanAnswer browser probes with a decoy page; needs ocserv 1.2.0 or newer.
camouflageSecretstringSecret in the connect URL: https://host:port/?SECRET.
camouflageRealmstringRealm shown to browsers that probe the port.
certSourcestringpki, panel or acme: where the server certificate comes from.
acmeHoststringACME DNS name; empty uses the node's public address.
idleTimeoutintegerIdle timeout for desktop clients, in seconds.
mobileIdleTimeoutintegerIdle timeout for mobile clients, in seconds.
cookieTimeoutintegerHow long a session cookie stays resumable, in seconds.
dpdintegerDead peer detection interval, in seconds.
mobileDpdintegerDead peer detection interval for mobile clients, in seconds.
ciscoCompatbooleanAccept old Cisco clients.
tlsPrioritiesstringGnuTLS priority string.
proxyProtocolbooleanAccept PROXY protocol headers from a relay.
serverCustomstringExtra ocserv.conf lines, checked against a denylist.

WireGuard settings (wg) ​

FieldTypeMeaning
filenameTemplatestringClient download filename: fixed text or {username}, {device}, {inbound} placeholders. Empty keeps automatic naming. WireGuard and AmneziaWG.
privateKeystringServer private key. Never returned by the API.
publicKeystringServer public key.
obfuscationstringObfuscation mode; empty means plain WireGuard.
amneziaobjectAmneziaWG parameters: jc, jmin, jmax, s1, s2, h1-h4, i1-i5, j1-j3, itime.
mtuintegerTunnel MTU.
keepaliveintegerPersistent keepalive in seconds; 0 means off.
allowedIPsstring[]CIDRs routed through the tunnel.

Preflight an inbound ​

POST/api/instances/preflightpermissioninbounds.manage

Checks a draft before creating it. The body is the create body plus nodeIds and per-node ports; nodeId is ignored. The answer has one finding per node, with an empty error when the node is ready.

bash
curl -sS -H "Authorization: Bearer $OVIRA_TOKEN" \
  -H "Content-Type: application/json" -X POST "$BASE/instances/preflight" \
  -d '{"kind":"openvpn","name":"udp1194","proto":"udp","port":1194,"network":"10.128.0.0/16","nodeIds":[0,4]}'
json
{
  "items": [
    { "nodeId": 0, "error": "" },
    { "nodeId": 4, "error": "port udp/1194 is already used by udp1194" }
  ]
}

400 means the draft itself is not valid.

Read defaults ​

GET/api/instances/defaultspermissioninbounds.manage

Returns the default settings for a new inbound. For OpenConnect it also returns the install state of the node.

ParameterInTypeMeaning
kindquerystringopenvpn, ocserv or wireguard. Default openvpn.
nodeIdqueryintegerNode the defaults are for. -1, the default, is an unassigned inbound.
bash
curl -sS -H "Authorization: Bearer $OVIRA_TOKEN" \
  "$BASE/instances/defaults?kind=openvpn&nodeId=0"
json
{
  "authMode": "cert",
  "tlsMode": "tls-crypt",
  "dataCiphers": ["AES-256-GCM", "CHACHA20-POLY1305"],
  "fallbackCipher": "",
  "authDigest": "SHA256",
  "tlsMinVersion": "1.2",
  "dns": ["1.1.1.1"],
  "redirectGateway": false,
  "blockOutsideDns": false,
  "pushRoutes": [],
  "ipv6": false,
  "network6": "",
  "clientToClient": false,
  "maxClients": 0,
  "keepaliveInterval": 10,
  "keepaliveTimeout": 60,
  "tunMtu": 0,
  "mssFix": 0,
  "fragment": 0,
  "sndRcvBuf": 0,
  "compression": "off",
  "renegSec": 0,
  "portShare": "",
  "exitNotify": false,
  "multihome": false,
  "remotes": [],
  "remote": "",
  "verb": 3,
  "nat": true,
  "serverCustom": "",
  "clientCustom": "",
  "description": ""
}

For kind=ocserv, the answer is an object with settings plus supported, installed, version, installing, installError, camouflageMin, camouflageOk, certSource, panelCert and acme.

Read inbound access ​

GET/api/instances/accesspermissioninbounds.manage

Returns the groups that may use each inbound, and how many clients have their own inbound list instead of a group.

bash
curl -sS -H "Authorization: Bearer $OVIRA_TOKEN" "$BASE/instances/access"
json
{
  "groups": [
    { "id": 3, "name": "Iran", "instances": [12, 21], "clients": 42 }
  ],
  "ownListClients": 7
}

Install OpenConnect on this server ​

POST/api/ocserv/installpermissioninbounds.manage

Starts installing ocserv on the panel host. The answer is 202; poll GET instances/defaults?kind=ocserv&nodeId=0 for the outcome on this server.

bash
curl -sS -H "Authorization: Bearer $OVIRA_TOKEN" -X POST "$BASE/ocserv/install"

400 means the install cannot run on this host.

Get one inbound ​

GET/api/instances/{id}permissioninbounds.view

Returns the inbound, the configuration file rendered for it, where that file lives, and its deployments and overrides. The account needs inbounds.view for all inbounds.

bash
curl -sS -H "Authorization: Bearer $OVIRA_TOKEN" "$BASE/instances/12"
json
{
  "instance": {
    "id": 12,
    "kind": "openvpn",
    "nodeId": 0,
    "name": "udp1194",
    "enabled": true,
    "proto": "udp",
    "port": 1194,
    "network": "10.128.0.0/16",
    "active": true,
    "state": "active",
    "clients": 42,
    "settings": { "authMode": "cert", "tlsMode": "tls-crypt" }
  },
  "config": "port 1194\nproto udp\n...",
  "path": "/etc/ovira/instances/udp1194/server.conf",
  "shared": { "name": "udp1194", "port": 1194 },
  "overrides": {},
  "deployments": []
}

Change an inbound ​

PUT/api/instances/{id}permissioninbounds.manage

Sends the same fields as create, without accessGroups, nodeIds and ports. The answer is the changed inbound with a warning when part of the change did not apply.

bash
curl -sS -H "Authorization: Bearer $OVIRA_TOKEN" \
  -H "Content-Type: application/json" -X PUT "$BASE/instances/12" \
  -d '{"name":"udp1194","enabled":true,"proto":"udp","port":1194,"network":"10.128.0.0/16","settings":{"authMode":"cert+pass","tlsMode":"tls-crypt"}}'
json
{
  "instance": {
    "id": 12,
    "name": "udp1194",
    "enabled": true,
    "port": 1194,
    "settings": { "authMode": "cert+pass", "tlsMode": "tls-crypt" }
  }
}

400 names the bad field. Changing a port or a network restarts the inbound and disconnects its users.

Delete an inbound ​

DELETE/api/instances/{id}permissioninbounds.manage

Removes the inbound and its service. Clients that used it lose that profile.

bash
curl -sS -H "Authorization: Bearer $OVIRA_TOKEN" -X DELETE "$BASE/instances/12"
json
{ "ok": true }

List deployments ​

GET/api/instances/{id}/deploymentspermissioninbounds.view

Returns one entry per node where the inbound is deployed, with the deployment job. The account needs inbounds.view for all inbounds.

bash
curl -sS -H "Authorization: Bearer $OVIRA_TOKEN" "$BASE/instances/12/deployments"
json
{
  "items": [
    {
      "nodeId": 4,
      "node": "de-fra-1",
      "instance": { "id": 27, "parentId": 12, "nodeId": 4, "name": "udp1194" },
      "job": {
        "serviceId": 12,
        "nodeId": 4,
        "instanceId": 27,
        "status": "done",
        "stage": "running",
        "logs": [],
        "updatedAt": 1795919000
      }
    }
  ]
}

Deploy an inbound ​

POST/api/instances/{id}/deploymentspermissioninbounds.manage

Queues a deployment to one or more nodes.

FieldTypeRequiredMeaning
nodeIdsinteger[]yes1-100 nodes to deploy to.
portsobjectnoPort per node, keyed by node id.

Add ?check=1 to check the nodes instead of deploying: the answer is 200 with one finding per node and nothing changes. Without it the answer is 202 and the deployments are queued.

bash
curl -sS -H "Authorization: Bearer $OVIRA_TOKEN" \
  -H "Content-Type: application/json" \
  -X POST "$BASE/instances/12/deployments?check=1" \
  -d '{"nodeIds":[4],"ports":{"4":1194}}'
json
{
  "items": [
    { "nodeId": 4, "error": "" }
  ]
}

400 means no node, too many nodes or an invalid body.

Remove a deployment ​

DELETE/api/instances/{id}/deployments/{node}permissioninbounds.manage

Removes the inbound from one node. Path parameters are the inbound id and the node id; 0 is this server.

bash
curl -sS -H "Authorization: Bearer $OVIRA_TOKEN" \
  -X DELETE "$BASE/instances/12/deployments/4"
json
{ "ok": true }

400 means the id or node is not valid, or the inbound is not deployed there.

Change one node's overrides ​

PUT/api/instances/{id}/deployments/{node}/overridespermissioninbounds.manage

Sets what one node overrides for a multi-node inbound. The answer is 202 and the node redeploys.

FieldTypeMeaning
portintegerPort on this node instead of the shared one.
networkstringTunnel network on this node instead of the shared one.
remotesobject[]Client addresses for this node instead of the shared ones: label, host, port.
bash
curl -sS -H "Authorization: Bearer $OVIRA_TOKEN" \
  -H "Content-Type: application/json" \
  -X PUT "$BASE/instances/12/deployments/4/overrides" \
  -d '{"port":443,"remotes":[{"label":"Germany","host":"de.example.com","port":443}]}'
json
{ "ok": true }

400 means the inbound is not deployed on that node.

DELETE/api/instances/{id}/deployments/{node}/overridespermissioninbounds.manage

Clears that node's overrides and redeploys it. The answer is 202.

Assign an inbound to a node ​

POST/api/instances/{id}/nodepermissioninbounds.manage

Moves an inbound to a node, including from one node to another. The body has one required field:

FieldTypeRequiredMeaning
nodeIdintegeryesNode to assign. 0 is the panel's own server.
bash
curl -sS -H "Authorization: Bearer $OVIRA_TOKEN" \
  -H "Content-Type: application/json" -X POST "$BASE/instances/12/node" \
  -d '{"nodeId":4}'

The answer is the inbound and a warning when part of it did not apply. 400 means no node was chosen or it is not valid.

DELETE/api/instances/{id}/nodepermissioninbounds.manage

Removes the inbound from its node and leaves it unassigned. Its profiles stop until it is assigned again.

bash
curl -sS -H "Authorization: Bearer $OVIRA_TOKEN" -X DELETE "$BASE/instances/12/node"

400 means the inbound cannot be unassigned.

Start, stop or restart an inbound ​

POST/api/instances/{id}/controlpermissioninbounds.manage
FieldTypeRequiredMeaning
actionstringyesstart, stop or restart.
bash
curl -sS -H "Authorization: Bearer $OVIRA_TOKEN" \
  -H "Content-Type: application/json" -X POST "$BASE/instances/12/control" \
  -d '{"action":"restart"}'

The answer is the inbound after the action. 400 means the action is not valid.

Read inbound logs ​

Requires inbounds.view: all.

GET/api/instances/{id}/logspermissioninbounds.view
ParameterInTypeMeaning
idpathintegerInbound id.
linesqueryintegerHow many lines, 10-2000. Anything else means 200.
bash
curl -sS -H "Authorization: Bearer $OVIRA_TOKEN" \
  "$BASE/instances/12/logs?lines=100"
json
{
  "logs": "2026-11-02 12:00:01 TLS: Initial packet from 203.0.113.9:51820\n..."
}

404 means no such inbound.

Proprietary software · documentation free to share