Update a VPN configuration
curl --request PUT \
--url https://closedvpn.io/auth/update-vpn-config/{id} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "Updated Gateway Name",
"config": {
"location": "Frankfurt, Germany",
"coordinates": [
50.1109,
8.6821
],
"usage_percentage": 45,
"img": "/img/countries/DE.png",
"access": [
"[email protected]"
],
"orgs": [
"<string>"
],
"commands": {
"create_cert": "/opt/vpn/create-client.sh CLIENT_NAME",
"get_users_stats": "/opt/vpn/user-stats.sh CLIENT_NAME"
},
"private": {
"server": "vpn-fra.closedvpn.io",
"port": 22,
"user": "vpnadmin",
"ssh_public_key": "<string>"
}
}
}
'import requests
url = "https://closedvpn.io/auth/update-vpn-config/{id}"
payload = {
"name": "Updated Gateway Name",
"config": {
"location": "Frankfurt, Germany",
"coordinates": [50.1109, 8.6821],
"usage_percentage": 45,
"img": "/img/countries/DE.png",
"access": ["[email protected]"],
"orgs": ["<string>"],
"commands": {
"create_cert": "/opt/vpn/create-client.sh CLIENT_NAME",
"get_users_stats": "/opt/vpn/user-stats.sh CLIENT_NAME"
},
"private": {
"server": "vpn-fra.closedvpn.io",
"port": 22,
"user": "vpnadmin",
"ssh_public_key": "<string>"
}
}
}
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({
name: 'Updated Gateway Name',
config: {
location: 'Frankfurt, Germany',
coordinates: [50.1109, 8.6821],
usage_percentage: 45,
img: '/img/countries/DE.png',
access: ['[email protected]'],
orgs: ['<string>'],
commands: {
create_cert: '/opt/vpn/create-client.sh CLIENT_NAME',
get_users_stats: '/opt/vpn/user-stats.sh CLIENT_NAME'
},
private: {
server: 'vpn-fra.closedvpn.io',
port: 22,
user: 'vpnadmin',
ssh_public_key: '<string>'
}
}
})
};
fetch('https://closedvpn.io/auth/update-vpn-config/{id}', 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://closedvpn.io/auth/update-vpn-config/{id}",
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([
'name' => 'Updated Gateway Name',
'config' => [
'location' => 'Frankfurt, Germany',
'coordinates' => [
50.1109,
8.6821
],
'usage_percentage' => 45,
'img' => '/img/countries/DE.png',
'access' => [
'[email protected]'
],
'orgs' => [
'<string>'
],
'commands' => [
'create_cert' => '/opt/vpn/create-client.sh CLIENT_NAME',
'get_users_stats' => '/opt/vpn/user-stats.sh CLIENT_NAME'
],
'private' => [
'server' => 'vpn-fra.closedvpn.io',
'port' => 22,
'user' => 'vpnadmin',
'ssh_public_key' => '<string>'
]
]
]),
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://closedvpn.io/auth/update-vpn-config/{id}"
payload := strings.NewReader("{\n \"name\": \"Updated Gateway Name\",\n \"config\": {\n \"location\": \"Frankfurt, Germany\",\n \"coordinates\": [\n 50.1109,\n 8.6821\n ],\n \"usage_percentage\": 45,\n \"img\": \"/img/countries/DE.png\",\n \"access\": [\n \"[email protected]\"\n ],\n \"orgs\": [\n \"<string>\"\n ],\n \"commands\": {\n \"create_cert\": \"/opt/vpn/create-client.sh CLIENT_NAME\",\n \"get_users_stats\": \"/opt/vpn/user-stats.sh CLIENT_NAME\"\n },\n \"private\": {\n \"server\": \"vpn-fra.closedvpn.io\",\n \"port\": 22,\n \"user\": \"vpnadmin\",\n \"ssh_public_key\": \"<string>\"\n }\n }\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://closedvpn.io/auth/update-vpn-config/{id}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"Updated Gateway Name\",\n \"config\": {\n \"location\": \"Frankfurt, Germany\",\n \"coordinates\": [\n 50.1109,\n 8.6821\n ],\n \"usage_percentage\": 45,\n \"img\": \"/img/countries/DE.png\",\n \"access\": [\n \"[email protected]\"\n ],\n \"orgs\": [\n \"<string>\"\n ],\n \"commands\": {\n \"create_cert\": \"/opt/vpn/create-client.sh CLIENT_NAME\",\n \"get_users_stats\": \"/opt/vpn/user-stats.sh CLIENT_NAME\"\n },\n \"private\": {\n \"server\": \"vpn-fra.closedvpn.io\",\n \"port\": 22,\n \"user\": \"vpnadmin\",\n \"ssh_public_key\": \"<string>\"\n }\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://closedvpn.io/auth/update-vpn-config/{id}")
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 \"name\": \"Updated Gateway Name\",\n \"config\": {\n \"location\": \"Frankfurt, Germany\",\n \"coordinates\": [\n 50.1109,\n 8.6821\n ],\n \"usage_percentage\": 45,\n \"img\": \"/img/countries/DE.png\",\n \"access\": [\n \"[email protected]\"\n ],\n \"orgs\": [\n \"<string>\"\n ],\n \"commands\": {\n \"create_cert\": \"/opt/vpn/create-client.sh CLIENT_NAME\",\n \"get_users_stats\": \"/opt/vpn/user-stats.sh CLIENT_NAME\"\n },\n \"private\": {\n \"server\": \"vpn-fra.closedvpn.io\",\n \"port\": 22,\n \"user\": \"vpnadmin\",\n \"ssh_public_key\": \"<string>\"\n }\n }\n}"
response = http.request(request)
puts response.read_body{
"message": "VPN configuration updated successfully",
"vpnConfig": {
"_id": "60c72b2f5f1b2c001c8e4b2a",
"name": "Frankfurt Node",
"config": {
"location": "Frankfurt, Germany",
"coordinates": [
50.1109,
8.6821
],
"usage_percentage": 45,
"img": "/img/countries/DE.png",
"access": [
"[email protected]"
],
"orgs": [
"<string>"
],
"commands": {
"create_cert": "/opt/vpn/create-client.sh CLIENT_NAME",
"get_users_stats": "/opt/vpn/user-stats.sh CLIENT_NAME"
},
"private": {
"server": "vpn-fra.closedvpn.io",
"port": 22,
"user": "vpnadmin",
"ssh_public_key": "<string>"
}
},
"users": [
"[email protected]"
],
"active": true,
"createdAt": 1735689600000,
"updatedAt": 1735689600000
}
}{
"message": "Unauthorized"
}{
"message": "You do not have permission to update this VPN configuration"
}{
"message": "VPN configuration not found or inactive"
}{
"message": "Error updating VPN configuration"
}VPN Configurations
Update VPN Configuration
Updates the name and/or config of an existing active VPN configuration. Supplying config replaces the entire document, so send the complete object including access, commands and private.
PUT
/
auth
/
update-vpn-config
/
{id}
Update a VPN configuration
curl --request PUT \
--url https://closedvpn.io/auth/update-vpn-config/{id} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "Updated Gateway Name",
"config": {
"location": "Frankfurt, Germany",
"coordinates": [
50.1109,
8.6821
],
"usage_percentage": 45,
"img": "/img/countries/DE.png",
"access": [
"[email protected]"
],
"orgs": [
"<string>"
],
"commands": {
"create_cert": "/opt/vpn/create-client.sh CLIENT_NAME",
"get_users_stats": "/opt/vpn/user-stats.sh CLIENT_NAME"
},
"private": {
"server": "vpn-fra.closedvpn.io",
"port": 22,
"user": "vpnadmin",
"ssh_public_key": "<string>"
}
}
}
'import requests
url = "https://closedvpn.io/auth/update-vpn-config/{id}"
payload = {
"name": "Updated Gateway Name",
"config": {
"location": "Frankfurt, Germany",
"coordinates": [50.1109, 8.6821],
"usage_percentage": 45,
"img": "/img/countries/DE.png",
"access": ["[email protected]"],
"orgs": ["<string>"],
"commands": {
"create_cert": "/opt/vpn/create-client.sh CLIENT_NAME",
"get_users_stats": "/opt/vpn/user-stats.sh CLIENT_NAME"
},
"private": {
"server": "vpn-fra.closedvpn.io",
"port": 22,
"user": "vpnadmin",
"ssh_public_key": "<string>"
}
}
}
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({
name: 'Updated Gateway Name',
config: {
location: 'Frankfurt, Germany',
coordinates: [50.1109, 8.6821],
usage_percentage: 45,
img: '/img/countries/DE.png',
access: ['[email protected]'],
orgs: ['<string>'],
commands: {
create_cert: '/opt/vpn/create-client.sh CLIENT_NAME',
get_users_stats: '/opt/vpn/user-stats.sh CLIENT_NAME'
},
private: {
server: 'vpn-fra.closedvpn.io',
port: 22,
user: 'vpnadmin',
ssh_public_key: '<string>'
}
}
})
};
fetch('https://closedvpn.io/auth/update-vpn-config/{id}', 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://closedvpn.io/auth/update-vpn-config/{id}",
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([
'name' => 'Updated Gateway Name',
'config' => [
'location' => 'Frankfurt, Germany',
'coordinates' => [
50.1109,
8.6821
],
'usage_percentage' => 45,
'img' => '/img/countries/DE.png',
'access' => [
'[email protected]'
],
'orgs' => [
'<string>'
],
'commands' => [
'create_cert' => '/opt/vpn/create-client.sh CLIENT_NAME',
'get_users_stats' => '/opt/vpn/user-stats.sh CLIENT_NAME'
],
'private' => [
'server' => 'vpn-fra.closedvpn.io',
'port' => 22,
'user' => 'vpnadmin',
'ssh_public_key' => '<string>'
]
]
]),
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://closedvpn.io/auth/update-vpn-config/{id}"
payload := strings.NewReader("{\n \"name\": \"Updated Gateway Name\",\n \"config\": {\n \"location\": \"Frankfurt, Germany\",\n \"coordinates\": [\n 50.1109,\n 8.6821\n ],\n \"usage_percentage\": 45,\n \"img\": \"/img/countries/DE.png\",\n \"access\": [\n \"[email protected]\"\n ],\n \"orgs\": [\n \"<string>\"\n ],\n \"commands\": {\n \"create_cert\": \"/opt/vpn/create-client.sh CLIENT_NAME\",\n \"get_users_stats\": \"/opt/vpn/user-stats.sh CLIENT_NAME\"\n },\n \"private\": {\n \"server\": \"vpn-fra.closedvpn.io\",\n \"port\": 22,\n \"user\": \"vpnadmin\",\n \"ssh_public_key\": \"<string>\"\n }\n }\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://closedvpn.io/auth/update-vpn-config/{id}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"Updated Gateway Name\",\n \"config\": {\n \"location\": \"Frankfurt, Germany\",\n \"coordinates\": [\n 50.1109,\n 8.6821\n ],\n \"usage_percentage\": 45,\n \"img\": \"/img/countries/DE.png\",\n \"access\": [\n \"[email protected]\"\n ],\n \"orgs\": [\n \"<string>\"\n ],\n \"commands\": {\n \"create_cert\": \"/opt/vpn/create-client.sh CLIENT_NAME\",\n \"get_users_stats\": \"/opt/vpn/user-stats.sh CLIENT_NAME\"\n },\n \"private\": {\n \"server\": \"vpn-fra.closedvpn.io\",\n \"port\": 22,\n \"user\": \"vpnadmin\",\n \"ssh_public_key\": \"<string>\"\n }\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://closedvpn.io/auth/update-vpn-config/{id}")
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 \"name\": \"Updated Gateway Name\",\n \"config\": {\n \"location\": \"Frankfurt, Germany\",\n \"coordinates\": [\n 50.1109,\n 8.6821\n ],\n \"usage_percentage\": 45,\n \"img\": \"/img/countries/DE.png\",\n \"access\": [\n \"[email protected]\"\n ],\n \"orgs\": [\n \"<string>\"\n ],\n \"commands\": {\n \"create_cert\": \"/opt/vpn/create-client.sh CLIENT_NAME\",\n \"get_users_stats\": \"/opt/vpn/user-stats.sh CLIENT_NAME\"\n },\n \"private\": {\n \"server\": \"vpn-fra.closedvpn.io\",\n \"port\": 22,\n \"user\": \"vpnadmin\",\n \"ssh_public_key\": \"<string>\"\n }\n }\n}"
response = http.request(request)
puts response.read_body{
"message": "VPN configuration updated successfully",
"vpnConfig": {
"_id": "60c72b2f5f1b2c001c8e4b2a",
"name": "Frankfurt Node",
"config": {
"location": "Frankfurt, Germany",
"coordinates": [
50.1109,
8.6821
],
"usage_percentage": 45,
"img": "/img/countries/DE.png",
"access": [
"[email protected]"
],
"orgs": [
"<string>"
],
"commands": {
"create_cert": "/opt/vpn/create-client.sh CLIENT_NAME",
"get_users_stats": "/opt/vpn/user-stats.sh CLIENT_NAME"
},
"private": {
"server": "vpn-fra.closedvpn.io",
"port": 22,
"user": "vpnadmin",
"ssh_public_key": "<string>"
}
},
"users": [
"[email protected]"
],
"active": true,
"createdAt": 1735689600000,
"updatedAt": 1735689600000
}
}{
"message": "Unauthorized"
}{
"message": "You do not have permission to update this VPN configuration"
}{
"message": "VPN configuration not found or inactive"
}{
"message": "Error updating VPN configuration"
}Authorizations
Personal Access Token (PAT) passed in the Authorization header (e.g., Bearer <pat>) for authenticated API requests. PATs are generated via /auth/generate-pat after authenticating through the magic link flow.
Path Parameters
Example:
"60c72b2f5f1b2c001c8e4b1a"
Body
application/json

