curl --request PUT \
--url https://api.kombify.io/v1/techstack/api/v1/servers/{serverId}/reach \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"enabled": true,
"service": "<string>",
"target_port": 32768,
"target_scheme": "http"
}
'import requests
url = "https://api.kombify.io/v1/techstack/api/v1/servers/{serverId}/reach"
payload = {
"enabled": True,
"service": "<string>",
"target_port": 32768,
"target_scheme": "http"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({enabled: true, service: '<string>', target_port: 32768, target_scheme: 'http'})
};
fetch('https://api.kombify.io/v1/techstack/api/v1/servers/{serverId}/reach', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.kombify.io/v1/techstack/api/v1/servers/{serverId}/reach",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'enabled' => true,
'service' => '<string>',
'target_port' => 32768,
'target_scheme' => 'http'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.kombify.io/v1/techstack/api/v1/servers/{serverId}/reach"
payload := strings.NewReader("{\n \"enabled\": true,\n \"service\": \"<string>\",\n \"target_port\": 32768,\n \"target_scheme\": \"http\"\n}")
req, _ := http.NewRequest("PUT", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.put("https://api.kombify.io/v1/techstack/api/v1/servers/{serverId}/reach")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"enabled\": true,\n \"service\": \"<string>\",\n \"target_port\": 32768,\n \"target_scheme\": \"http\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.kombify.io/v1/techstack/api/v1/servers/{serverId}/reach")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"enabled\": true,\n \"service\": \"<string>\",\n \"target_port\": 32768,\n \"target_scheme\": \"http\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"state": "not_enrolled",
"kombify_me": {
"state": "pending",
"address": "<string>",
"node_id": "<string>",
"reason_code": "<string>"
},
"connect": {
"state": "pending",
"address": "<string>",
"node_id": "<string>",
"reason_code": "<string>"
},
"updated_at": "2023-11-07T05:31:56Z",
"generation": 123,
"public": {
"enabled": true,
"service": "<string>",
"scheme": "http",
"target_port": 32768,
"enabled_by": "<string>",
"enabled_at": "2023-11-07T05:31:56Z"
},
"relay": {
"state": "connecting",
"reason_code": "<string>",
"reported_at": "2023-11-07T05:31:56Z"
}
},
"meta": {
"total": 123,
"page": 123,
"per_page": 123,
"managed_runtime_inventory_complete": true,
"worker_inventory_sha256": "<string>",
"managed_runtime_active_lease_ids": [
"<string>"
],
"managed_runtime_inactive_lease_ids": [
"<string>"
],
"managed_runtime_lease_generation_digests": [
{
"lease_id": "<string>",
"resource_generation_digest": "<string>"
}
],
"managed_runtime_duplicate_lease_ids": [
"<string>"
],
"managed_runtime_attachment_conflict_lease_ids": [
"<string>"
]
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "<string>",
"details": "<unknown>"
}
}Publish the server at a kombify.me address, or stop publishing it
Nothing is published by default: a paired server has no public route and the relay carries no traffic. The owner enables it per server with an explicit service name and target_port (the origin is always the Guard host’s loopback, never another machine) and may withdraw it at any time. The relay authenticates the Guard, not the visitor, so what answers on that port must protect itself. Enabling requires the owner, the techstack.servers.maintenance entitlement and a fresh multi-factor sign-in (reason server_reach_step_up_required); withdrawing is never gated. Responds with the reach section of the server read model; the reconciler then creates or withdraws the route.
curl --request PUT \
--url https://api.kombify.io/v1/techstack/api/v1/servers/{serverId}/reach \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"enabled": true,
"service": "<string>",
"target_port": 32768,
"target_scheme": "http"
}
'import requests
url = "https://api.kombify.io/v1/techstack/api/v1/servers/{serverId}/reach"
payload = {
"enabled": True,
"service": "<string>",
"target_port": 32768,
"target_scheme": "http"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({enabled: true, service: '<string>', target_port: 32768, target_scheme: 'http'})
};
fetch('https://api.kombify.io/v1/techstack/api/v1/servers/{serverId}/reach', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.kombify.io/v1/techstack/api/v1/servers/{serverId}/reach",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'enabled' => true,
'service' => '<string>',
'target_port' => 32768,
'target_scheme' => 'http'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.kombify.io/v1/techstack/api/v1/servers/{serverId}/reach"
payload := strings.NewReader("{\n \"enabled\": true,\n \"service\": \"<string>\",\n \"target_port\": 32768,\n \"target_scheme\": \"http\"\n}")
req, _ := http.NewRequest("PUT", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.put("https://api.kombify.io/v1/techstack/api/v1/servers/{serverId}/reach")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"enabled\": true,\n \"service\": \"<string>\",\n \"target_port\": 32768,\n \"target_scheme\": \"http\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.kombify.io/v1/techstack/api/v1/servers/{serverId}/reach")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"enabled\": true,\n \"service\": \"<string>\",\n \"target_port\": 32768,\n \"target_scheme\": \"http\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"state": "not_enrolled",
"kombify_me": {
"state": "pending",
"address": "<string>",
"node_id": "<string>",
"reason_code": "<string>"
},
"connect": {
"state": "pending",
"address": "<string>",
"node_id": "<string>",
"reason_code": "<string>"
},
"updated_at": "2023-11-07T05:31:56Z",
"generation": 123,
"public": {
"enabled": true,
"service": "<string>",
"scheme": "http",
"target_port": 32768,
"enabled_by": "<string>",
"enabled_at": "2023-11-07T05:31:56Z"
},
"relay": {
"state": "connecting",
"reason_code": "<string>",
"reported_at": "2023-11-07T05:31:56Z"
}
},
"meta": {
"total": 123,
"page": 123,
"per_page": 123,
"managed_runtime_inventory_complete": true,
"worker_inventory_sha256": "<string>",
"managed_runtime_active_lease_ids": [
"<string>"
],
"managed_runtime_inactive_lease_ids": [
"<string>"
],
"managed_runtime_lease_generation_digests": [
{
"lease_id": "<string>",
"resource_generation_digest": "<string>"
}
],
"managed_runtime_duplicate_lease_ids": [
"<string>"
],
"managed_runtime_attachment_conflict_lease_ids": [
"<string>"
]
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "<string>",
"details": "<unknown>"
}
}授权
OIDC/JWKS bearer token. Self-hosted defaults to Pocket ID; SaaS uses Auth0 through the edge. PocketBase JWT is legacy migration compatibility only.
路径参数
Canonical server runtime ID
请求体
Required when enabling. The route label; the kombify.me route is --.
^[a-z]([a-z0-9-]{0,12}[a-z0-9])?$Required when enabling. The port the service listens on, on the Guard host's loopback (the host is fixed).
1 <= x <= 65535http, https 响应
The reach section after the change
kombify Guard reach, persisted and never derived client-side: whether the server's kombify.me address answers through the Guard relay and whether the server is listed as a Connect resource. ready is shown as "Reachable and governed". A reach failure never blocks Guard enrollment or execution and never changes the server lifecycle. Absent on deployments without a Cloud connection.
Show child attributes
Show child attributes
Show child attributes
Show child attributes
