---
title: "Networking — API reference"
description: "Reverse DNS and the inbound firewall of a server."
url: https://www.gyrohosting.com/developers/en/api/networking.html
language: en
openapi: https://www.gyrohosting.com/developers/openapi.json
api_version: 2.30.0
---

# Networking

Reverse DNS and the inbound firewall of a server.

Base URL: `https://www.gyrohosting.com/api/v1/client` · OpenAPI: https://www.gyrohosting.com/developers/openapi.json


## GET /cloud/servers/{id}/rdns

**List reverse DNS entries** · operationId `listRdns` · scope `cloud_read` · OpenAPI fragment: https://www.gyrohosting.com/developers/spec/ops/listRdns.json

**tr-ist-1 (Gyro Bulut İstanbul):** every address (primary and additional IPv4) gets an automatic PTR `<a-b-c-d>.ip.gyrohosting.com` with a matching A record. Set `hostname` to your own FQDN to replace it (published within seconds); an empty value restores the default. Names under Gyro domains and protected brand names are refused (HTTP 422 with an explanatory message); at most 30 changes per server per hour. The A record of your name should point to the address (forward-confirmed reverse DNS) for e-mail delivery; it is not enforced. When the server is deleted or an additional IP is released, its PTR is removed. 


### Parameters

| Field | in | Type | Description |
|---|---|---|---|
| `id` (required) | path | integer | Server id (= service id in the client area) |

### Responses

- **200**: PTR records of the server's addresses
- **404**: Not found — also returned for objects owned by someone else

### Examples

```bash
curl -s 'https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/rdns' \
  -H "Authorization: Bearer $GYRO_TOKEN"
```
```bash
gyro server rdns list 12345
```
```hcl
# resource gyro_server_rdns: https://registry.terraform.io/providers/gyro-hosting/gyro/latest/docs/resources/server_rdns
resource "gyro_server_rdns" "mail" {
  server_id = gyro_server.web.id
  ip        = gyro_server.web.ipv4
  hostname  = "mail.example.com"
}
```
```python
import os, uuid, requests

h = {"Authorization": "Bearer " + os.environ["GYRO_TOKEN"]}
r = requests.get("https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/rdns", headers=h, timeout=60)
r.raise_for_status()
print(r.json()["data"])
```
```js
const res = await fetch("https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/rdns", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${process.env.GYRO_TOKEN}`,
  },
});
const { data, error } = await res.json();
if (!res.ok) throw new Error(`${error.code}: ${error.message}`);
```


## PUT /cloud/servers/{id}/rdns

**Set (or reset) the PTR record of one address** · operationId `setRdns` · scope `cloud_write` · OpenAPI fragment: https://www.gyrohosting.com/developers/spec/ops/setRdns.json

**tr-ist-1 (Gyro Bulut İstanbul):** every address (primary and additional IPv4) gets an automatic PTR `<a-b-c-d>.ip.gyrohosting.com` with a matching A record. Set `hostname` to your own FQDN to replace it (published within seconds); an empty value restores the default. Names under Gyro domains and protected brand names are refused (HTTP 422 with an explanatory message); at most 30 changes per server per hour. The A record of your name should point to the address (forward-confirmed reverse DNS) for e-mail delivery; it is not enforced. When the server is deleted or an additional IP is released, its PTR is removed. `dns_ptr` and `ptr` are accepted as aliases of `hostname`. Legacy Istanbul VDS servers keep the request flow (`status: pending` until applied).


### Parameters

| Field | in | Type | Description |
|---|---|---|---|
| `id` (required) | path | integer | Server id (= service id in the client area) |

### Request body

| Field | Type | Description |
|---|---|---|
| `ip` (required) | string | An address of this server (IPv6 addresses inside the server's /64 are allowed) |
| `hostname` | string | FQDN; empty string resets to the default |

### Responses

- **200**: Updated list
- **404**: Not found — also returned for objects owned by someone else
- **422**: Validation or business rule failure (`confirm_required`, `invalid_image`, `tool_action_failed` ...)

### Examples

```bash
curl -s -X PUT 'https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/rdns' \
  -H "Authorization: Bearer $GYRO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"ip": "string", "hostname": "string"}'
```
```bash
gyro server rdns set 12345 --help    # all flags
```
```hcl
# resource gyro_server_rdns: https://registry.terraform.io/providers/gyro-hosting/gyro/latest/docs/resources/server_rdns
resource "gyro_server_rdns" "mail" {
  server_id = gyro_server.web.id
  ip        = gyro_server.web.ipv4
  hostname  = "mail.example.com"
}
```
```python
import os, uuid, requests

h = {"Authorization": "Bearer " + os.environ["GYRO_TOKEN"]}
r = requests.put("https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/rdns", headers=h, json={"ip": "string", "hostname": "string"}, timeout=60)
r.raise_for_status()
print(r.json()["data"])
```
```js
const res = await fetch("https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/rdns", {
  method: "PUT",
  headers: {
    "Authorization": `Bearer ${process.env.GYRO_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({"ip": "string", "hostname": "string"}),
});
const { data, error } = await res.json();
if (!res.ok) throw new Error(`${error.code}: ${error.message}`);
```


## GET /cloud/servers/{id}/firewall

**Inbound firewall rules** · operationId `getFirewall` · scope `cloud_read` · OpenAPI fragment: https://www.gyrohosting.com/developers/spec/ops/getFirewall.json

Read-only in v1. An empty list means no Gyro firewall is applied (all inbound traffic reaches the server). tr-ist-1: rules come from the network firewall add-on (security groups); without the add-on the list is empty and writes answer 409 `firewall_not_enabled`.


### Parameters

| Field | in | Type | Description |
|---|---|---|---|
| `id` (required) | path | integer | Server id (= service id in the client area) |

### Responses

- **200**: Rules
- **404**: Not found — also returned for objects owned by someone else

### Examples

```bash
curl -s 'https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/firewall' \
  -H "Authorization: Bearer $GYRO_TOKEN"
```
```bash
gyro server firewall list 12345
```
```hcl
# resource gyro_firewall: https://registry.terraform.io/providers/gyro-hosting/gyro/latest/docs/resources/firewall
# Web server: 80/443 open to everyone, SSH only from the office, everything else denied.
resource "gyro_firewall" "web" {
  server_id      = 1234
  default_action = "deny"

  rule {
    action      = "allow"
    protocol    = "tcp"
    port        = "80,443"
    description = "web"
  }
  rule {
    action   = "allow"
    protocol = "udp"
    port     = "443"
  }
  rule {
    action = "allow"
    port   = "22"
    source = "203.0.113.10"
  }
}

# Database: open, but 3306 closed to one address; outbound SMTP blocked.
resource "gyro_firewall" "db" {
  server_id      = 1235
  default_action = "allow"

  rule {
    action = "deny"
    port   = "3306"
    source = "198.51.100.7"
  }
  rule {
    direction = "out"
    action    = "deny"
    port      = "25"
  }
}
```
```python
import os, uuid, requests

h = {"Authorization": "Bearer " + os.environ["GYRO_TOKEN"]}
r = requests.get("https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/firewall", headers=h, timeout=60)
r.raise_for_status()
print(r.json()["data"])
```
```js
const res = await fetch("https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/firewall", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${process.env.GYRO_TOKEN}`,
  },
});
const { data, error } = await res.json();
if (!res.ok) throw new Error(`${error.code}: ${error.message}`);
```


## POST /cloud/servers/{id}/firewall/rules

**Add a firewall rule** · operationId `addFirewallRule` · scope `cloud_write` · OpenAPI fragment: https://www.gyrohosting.com/developers/spec/ops/addFirewallRule.json

Network firewall add-on: inserts at `priority` (default last) and applies as a trial unless `permanent`. Otherwise the cloud server's simple inbound allow list.


### Parameters

| Field | in | Type | Description |
|---|---|---|---|
| `id` (required) | path | integer | Server id (= service id in the client area) |

### Request body

| Field | Type | Description |
|---|---|---|
| `priority` | integer | Position (1 = evaluated first). Default = last. First matching rule wins. |
| `direction` | string (in, out) | in = inbound to the server, out = new outbound connections (network firewall only) |
| `action` | string (allow, deny) |  |
| `protocol` | string (tcp, udp, tcp_udp, icmp, all) |  |
| `source` | string | any / IPv4/CIDR list (comma separated, max 10). For direction out: the remote address. Country sources (country:XX / not-country:XX) are accepted only when capabilities.country_filter is true (currently not offered). |
| `destination` | string | any (all IPs of the server) or one IP address of the server |
| `port` | string | any / 22 / 80,443 / 1000-2000 (not for icmp/all) |
| `description` | string |  |
| `source_ips` | array<string> | Legacy - CIDRs (use source) |
| `permanent` | boolean | Network firewall - skip the 5 minute trial and make the change permanent at once |
| `confirm_warnings` | boolean | Apply even when the change has warnings (lock-out risk, shadowed or duplicate rules, private sources) |

### Responses

- **201**: All rules after the change
- **404**: Not found — also returned for objects owned by someone else
- **422**: Validation or business rule failure (`confirm_required`, `invalid_image`, `tool_action_failed` ...)

### Examples

```bash
curl -s -X POST 'https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/firewall/rules' \
  -H "Authorization: Bearer $GYRO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"protocol": "tcp", "port": "22", "source_ips": ["203.0.113.0/24"]}'
```
```bash
gyro server firewall rule add 12345 --help    # all flags
```
```hcl
# resource gyro_firewall: https://registry.terraform.io/providers/gyro-hosting/gyro/latest/docs/resources/firewall
# Web server: 80/443 open to everyone, SSH only from the office, everything else denied.
resource "gyro_firewall" "web" {
  server_id      = 1234
  default_action = "deny"

  rule {
    action      = "allow"
    protocol    = "tcp"
    port        = "80,443"
    description = "web"
  }
  rule {
    action   = "allow"
    protocol = "udp"
    port     = "443"
  }
  rule {
    action = "allow"
    port   = "22"
    source = "203.0.113.10"
  }
}

# Database: open, but 3306 closed to one address; outbound SMTP blocked.
resource "gyro_firewall" "db" {
  server_id      = 1235
  default_action = "allow"

  rule {
    action = "deny"
    port   = "3306"
    source = "198.51.100.7"
  }
  rule {
    direction = "out"
    action    = "deny"
    port      = "25"
  }
}
```
```python
import os, uuid, requests

h = {"Authorization": "Bearer " + os.environ["GYRO_TOKEN"]}
r = requests.post("https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/firewall/rules", headers=h, json={"protocol": "tcp", "port": "22", "source_ips": ["203.0.113.0/24"]}, timeout=60)
r.raise_for_status()
print(r.json()["data"])
```
```js
const res = await fetch("https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/firewall/rules", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.GYRO_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({"protocol": "tcp", "port": "22", "source_ips": ["203.0.113.0/24"]}),
});
const { data, error } = await res.json();
if (!res.ok) throw new Error(`${error.code}: ${error.message}`);
```


## DELETE /cloud/servers/{id}/firewall/rules/{n}

**Remove a firewall rule (the last one needs confirm)** · operationId `deleteFirewallRule` · scope `cloud_write` · OpenAPI fragment: https://www.gyrohosting.com/developers/spec/ops/deleteFirewallRule.json




### Parameters

| Field | in | Type | Description |
|---|---|---|---|
| `id` (required) | path | integer | Server id (= service id in the client area) |
| `n` (required) | path | integer | 1-based position from GET /firewall |
| `confirm` | query | boolean |  |

### Responses

- **200**: Remaining rules
- **404**: Not found — also returned for objects owned by someone else
- **422**: Validation or business rule failure (`confirm_required`, `invalid_image`, `tool_action_failed` ...)

### Examples

```bash
curl -s -X DELETE 'https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/firewall/rules/1' \
  -H "Authorization: Bearer $GYRO_TOKEN"
```
```bash
gyro server firewall rule delete 12345
```
```hcl
# resource gyro_firewall: https://registry.terraform.io/providers/gyro-hosting/gyro/latest/docs/resources/firewall
# Web server: 80/443 open to everyone, SSH only from the office, everything else denied.
resource "gyro_firewall" "web" {
  server_id      = 1234
  default_action = "deny"

  rule {
    action      = "allow"
    protocol    = "tcp"
    port        = "80,443"
    description = "web"
  }
  rule {
    action   = "allow"
    protocol = "udp"
    port     = "443"
  }
  rule {
    action = "allow"
    port   = "22"
    source = "203.0.113.10"
  }
}

# Database: open, but 3306 closed to one address; outbound SMTP blocked.
resource "gyro_firewall" "db" {
  server_id      = 1235
  default_action = "allow"

  rule {
    action = "deny"
    port   = "3306"
    source = "198.51.100.7"
  }
  rule {
    direction = "out"
    action    = "deny"
    port      = "25"
  }
}
```
```python
import os, uuid, requests

h = {"Authorization": "Bearer " + os.environ["GYRO_TOKEN"]}
r = requests.delete("https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/firewall/rules/1", headers=h, timeout=60)
r.raise_for_status()
print(r.json()["data"])
```
```js
const res = await fetch("https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/firewall/rules/1", {
  method: "DELETE",
  headers: {
    "Authorization": `Bearer ${process.env.GYRO_TOKEN}`,
  },
});
const { data, error } = await res.json();
if (!res.ok) throw new Error(`${error.code}: ${error.message}`);
```


## GET /cloud/servers/{id}/firewall/policy

**Network firewall policy (rules, default action, status)** · operationId `getFirewallPolicy` · scope `cloud_read` · OpenAPI fragment: https://www.gyrohosting.com/developers/spec/ops/getFirewallPolicy.json




### Parameters

| Field | in | Type | Description |
|---|---|---|---|
| `id` (required) | path | integer | Server id (= service id in the client area) |

### Responses

- **200**: Policy
- **404**: Not found — also returned for objects owned by someone else
- **409**: The network firewall add-on is not active on this server (firewall_not_enabled)

### Examples

```bash
curl -s 'https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/firewall/policy' \
  -H "Authorization: Bearer $GYRO_TOKEN"
```
```bash
gyro firewall get 12345
```
```hcl
# resource gyro_firewall: https://registry.terraform.io/providers/gyro-hosting/gyro/latest/docs/resources/firewall
# Web server: 80/443 open to everyone, SSH only from the office, everything else denied.
resource "gyro_firewall" "web" {
  server_id      = 1234
  default_action = "deny"

  rule {
    action      = "allow"
    protocol    = "tcp"
    port        = "80,443"
    description = "web"
  }
  rule {
    action   = "allow"
    protocol = "udp"
    port     = "443"
  }
  rule {
    action = "allow"
    port   = "22"
    source = "203.0.113.10"
  }
}

# Database: open, but 3306 closed to one address; outbound SMTP blocked.
resource "gyro_firewall" "db" {
  server_id      = 1235
  default_action = "allow"

  rule {
    action = "deny"
    port   = "3306"
    source = "198.51.100.7"
  }
  rule {
    direction = "out"
    action    = "deny"
    port      = "25"
  }
}
```
```python
import os, uuid, requests

h = {"Authorization": "Bearer " + os.environ["GYRO_TOKEN"]}
r = requests.get("https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/firewall/policy", headers=h, timeout=60)
r.raise_for_status()
print(r.json()["data"])
```
```js
const res = await fetch("https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/firewall/policy", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${process.env.GYRO_TOKEN}`,
  },
});
const { data, error } = await res.json();
if (!res.ok) throw new Error(`${error.code}: ${error.message}`);
```


## PUT /cloud/servers/{id}/firewall/policy

**Replace the network firewall policy** · operationId `putFirewallPolicy` · scope `cloud_write` · OpenAPI fragment: https://www.gyrohosting.com/developers/spec/ops/putFirewallPolicy.json

Applies as a 5 minute trial unless `permanent` is true; confirm with POST /firewall/policy/confirm. Warnings return 422 `confirm_warnings_required` with `details.warnings`.


### Parameters

| Field | in | Type | Description |
|---|---|---|---|
| `id` (required) | path | integer | Server id (= service id in the client area) |

### Request body

| Field | Type | Description |
|---|---|---|
| `default_action` | string (allow, deny) |  |
| `ping` | boolean |  |
| `rules` (required) | array<FirewallRuleInput> |  |
| `permanent` | boolean | Skip the 5 minute trial (otherwise call POST /firewall/policy/confirm within 5 minutes or the change is reverted) |
| `confirm_warnings` | boolean |  |

### Responses

- **200**: Policy after the change
- **404**: Not found — also returned for objects owned by someone else
- **409**: firewall_not_enabled
- **422**: Validation or business rule failure (`confirm_required`, `invalid_image`, `tool_action_failed` ...)

### Examples

```bash
curl -s -X PUT 'https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/firewall/policy' \
  -H "Authorization: Bearer $GYRO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"default_action": "deny", "rules": [{"action": "allow", "protocol": "tcp", "port": "80,443", "source": "any"}, {"action": "allow", "protocol": "tcp", "port": "22", "source": "203.0.113.10"}]}'
```
```bash
gyro firewall set 12345 --help    # all flags
```
```hcl
# resource gyro_firewall: https://registry.terraform.io/providers/gyro-hosting/gyro/latest/docs/resources/firewall
# Web server: 80/443 open to everyone, SSH only from the office, everything else denied.
resource "gyro_firewall" "web" {
  server_id      = 1234
  default_action = "deny"

  rule {
    action      = "allow"
    protocol    = "tcp"
    port        = "80,443"
    description = "web"
  }
  rule {
    action   = "allow"
    protocol = "udp"
    port     = "443"
  }
  rule {
    action = "allow"
    port   = "22"
    source = "203.0.113.10"
  }
}

# Database: open, but 3306 closed to one address; outbound SMTP blocked.
resource "gyro_firewall" "db" {
  server_id      = 1235
  default_action = "allow"

  rule {
    action = "deny"
    port   = "3306"
    source = "198.51.100.7"
  }
  rule {
    direction = "out"
    action    = "deny"
    port      = "25"
  }
}
```
```python
import os, uuid, requests

h = {"Authorization": "Bearer " + os.environ["GYRO_TOKEN"]}
r = requests.put("https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/firewall/policy", headers=h, json={"default_action": "deny", "rules": [{"action": "allow", "protocol": "tcp", "port": "80,443", "source": "any"}, {"action": "allow", "protocol": "tcp", "port": "22", "source": "203.0.113.10"}]}, timeout=60)
r.raise_for_status()
print(r.json()["data"])
```
```js
const res = await fetch("https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/firewall/policy", {
  method: "PUT",
  headers: {
    "Authorization": `Bearer ${process.env.GYRO_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({"default_action": "deny", "rules": [{"action": "allow", "protocol": "tcp", "port": "80,443", "source": "any"}, {"action": "allow", "protocol": "tcp", "port": "22", "source": "203.0.113.10"}]}),
});
const { data, error } = await res.json();
if (!res.ok) throw new Error(`${error.code}: ${error.message}`);
```


## DELETE /cloud/servers/{id}/firewall/policy

**Remove your firewall rules** · operationId `deleteFirewallPolicy` · scope `cloud_write` · OpenAPI fragment: https://www.gyrohosting.com/developers/spec/ops/deleteFirewallPolicy.json

Removes every customer rule of the server (all traffic allowed). Rules applied by Gyro support stay.


### Parameters

| Field | in | Type | Description |
|---|---|---|---|
| `id` (required) | path | integer | Server id (= service id in the client area) |

### Responses

- **200**: Policy after the change
- **404**: Not found — also returned for objects owned by someone else
- **409**: firewall_not_enabled

### Examples

```bash
curl -s -X DELETE 'https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/firewall/policy' \
  -H "Authorization: Bearer $GYRO_TOKEN"
```
```bash
gyro firewall delete 12345
```
```hcl
# resource gyro_firewall: https://registry.terraform.io/providers/gyro-hosting/gyro/latest/docs/resources/firewall
# Web server: 80/443 open to everyone, SSH only from the office, everything else denied.
resource "gyro_firewall" "web" {
  server_id      = 1234
  default_action = "deny"

  rule {
    action      = "allow"
    protocol    = "tcp"
    port        = "80,443"
    description = "web"
  }
  rule {
    action   = "allow"
    protocol = "udp"
    port     = "443"
  }
  rule {
    action = "allow"
    port   = "22"
    source = "203.0.113.10"
  }
}

# Database: open, but 3306 closed to one address; outbound SMTP blocked.
resource "gyro_firewall" "db" {
  server_id      = 1235
  default_action = "allow"

  rule {
    action = "deny"
    port   = "3306"
    source = "198.51.100.7"
  }
  rule {
    direction = "out"
    action    = "deny"
    port      = "25"
  }
}
```
```python
import os, uuid, requests

h = {"Authorization": "Bearer " + os.environ["GYRO_TOKEN"]}
r = requests.delete("https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/firewall/policy", headers=h, timeout=60)
r.raise_for_status()
print(r.json()["data"])
```
```js
const res = await fetch("https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/firewall/policy", {
  method: "DELETE",
  headers: {
    "Authorization": `Bearer ${process.env.GYRO_TOKEN}`,
  },
});
const { data, error } = await res.json();
if (!res.ok) throw new Error(`${error.code}: ${error.message}`);
```


## POST /cloud/servers/{id}/firewall/policy/confirm

**Make the running firewall trial permanent** · operationId `confirmFirewallPolicy` · scope `cloud_write` · OpenAPI fragment: https://www.gyrohosting.com/developers/spec/ops/confirmFirewallPolicy.json




### Parameters

| Field | in | Type | Description |
|---|---|---|---|
| `id` (required) | path | integer | Server id (= service id in the client area) |

### Responses

- **200**: Policy
- **404**: Not found — also returned for objects owned by someone else
- **422**: Validation or business rule failure (`confirm_required`, `invalid_image`, `tool_action_failed` ...)

### Examples

```bash
curl -s -X POST 'https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/firewall/policy/confirm' \
  -H "Authorization: Bearer $GYRO_TOKEN"
```
```bash
gyro firewall confirm 12345
```
```hcl
# resource gyro_firewall: https://registry.terraform.io/providers/gyro-hosting/gyro/latest/docs/resources/firewall
# Web server: 80/443 open to everyone, SSH only from the office, everything else denied.
resource "gyro_firewall" "web" {
  server_id      = 1234
  default_action = "deny"

  rule {
    action      = "allow"
    protocol    = "tcp"
    port        = "80,443"
    description = "web"
  }
  rule {
    action   = "allow"
    protocol = "udp"
    port     = "443"
  }
  rule {
    action = "allow"
    port   = "22"
    source = "203.0.113.10"
  }
}

# Database: open, but 3306 closed to one address; outbound SMTP blocked.
resource "gyro_firewall" "db" {
  server_id      = 1235
  default_action = "allow"

  rule {
    action = "deny"
    port   = "3306"
    source = "198.51.100.7"
  }
  rule {
    direction = "out"
    action    = "deny"
    port      = "25"
  }
}
```
```python
import os, uuid, requests

h = {"Authorization": "Bearer " + os.environ["GYRO_TOKEN"]}
r = requests.post("https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/firewall/policy/confirm", headers=h, timeout=60)
r.raise_for_status()
print(r.json()["data"])
```
```js
const res = await fetch("https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/firewall/policy/confirm", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.GYRO_TOKEN}`,
  },
});
const { data, error } = await res.json();
if (!res.ok) throw new Error(`${error.code}: ${error.message}`);
```


## GET /cloud/servers/{id}/ips

**List the server's IPv4 addresses** · operationId `listServerIps` · scope `cloud_read` · OpenAPI fragment: https://www.gyrohosting.com/developers/spec/ops/listServerIps.json

**Minimum charge:** each added IP is billed for at least 6 hours (`pricing.minimum_hours`): releasing it earlier still bills the minimum (debited at release), and taking the same address again starts a new minimum. At most `adds_per_hour` addresses (default 10) can be added to a server per 60 minutes. Additional IPv4 addresses are billed per address hourly from the prepaid balance (default 2 EUR per address-month, `pricing` shows the current price), from the hour they are added until they are released. Up to `max` per server (default 5). Each address is configured on the server automatically (/32 on the primary interface, kept across reboots and reinstalls); reverse DNS: PUT /cloud/servers/{id}/rdns. 


### Parameters

| Field | in | Type | Description |
|---|---|---|---|
| `id` (required) | path | integer | Server id (tr-ist-1) |

### Responses

- **200**: OK
- **404**: Not found — also returned for objects owned by someone else
- **409**: not_actionable (suspended / busy)
- **422**: Validation or business rule failure (`confirm_required`, `invalid_image`, `tool_action_failed` ...)
- **501**: not_supported (not a tr-ist-1 Gyro Compute server)

### Examples

```bash
curl -s 'https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/ips' \
  -H "Authorization: Bearer $GYRO_TOKEN"
```
```bash
gyro server ip list 12345
```
```hcl
# resource gyro_server_ip: https://registry.terraform.io/providers/gyro-hosting/gyro/latest/docs/resources/server_ip
resource "gyro_server_ip" "extra" {
  count     = 2
  server_id = gyro_server.web.id
}

output "extra_ips" {
  value = gyro_server_ip.extra[*].ip
}
```
```python
import os, uuid, requests

h = {"Authorization": "Bearer " + os.environ["GYRO_TOKEN"]}
r = requests.get("https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/ips", headers=h, timeout=60)
r.raise_for_status()
print(r.json()["data"])
```
```js
const res = await fetch("https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/ips", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${process.env.GYRO_TOKEN}`,
  },
});
const { data, error } = await res.json();
if (!res.ok) throw new Error(`${error.code}: ${error.message}`);
```


## POST /cloud/servers/{id}/ips

**Add additional IPv4 addresses** · operationId `addServerIps` · scope `cloud_write` · OpenAPI fragment: https://www.gyrohosting.com/developers/spec/ops/addServerIps.json

**Minimum charge:** each added IP is billed for at least 6 hours (`pricing.minimum_hours`): releasing it earlier still bills the minimum (debited at release), and taking the same address again starts a new minimum. At most `adds_per_hour` addresses (default 10) can be added to a server per 60 minutes. Additional IPv4 addresses are billed per address hourly from the prepaid balance (default 2 EUR per address-month, `pricing` shows the current price), from the hour they are added until they are released. Up to `max` per server (default 5). Each address is configured on the server automatically (/32 on the primary interface, kept across reboots and reinstalls); reverse DNS: PUT /cloud/servers/{id}/rdns. Prepaid tr-ist-1 servers only; not while the server is suspended.


### Parameters

| Field | in | Type | Description |
|---|---|---|---|
| `id` (required) | path | integer | Server id (tr-ist-1) |

### Request body

| Field | Type | Description |
|---|---|---|
| `count` | integer |  |

### Responses

- **201**: OK
- **404**: Not found — also returned for objects owned by someone else
- **409**: not_actionable (suspended / busy)
- **422**: Validation or business rule failure (`confirm_required`, `invalid_image`, `tool_action_failed` ...)
- **501**: not_supported (not a tr-ist-1 Gyro Compute server)

### Examples

```bash
curl -s -X POST 'https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/ips' \
  -H "Authorization: Bearer $GYRO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"count": 1}'
```
```bash
gyro server ip add 12345 --help    # all flags
```
```hcl
# resource gyro_server_ip: https://registry.terraform.io/providers/gyro-hosting/gyro/latest/docs/resources/server_ip
resource "gyro_server_ip" "extra" {
  count     = 2
  server_id = gyro_server.web.id
}

output "extra_ips" {
  value = gyro_server_ip.extra[*].ip
}
```
```python
import os, uuid, requests

h = {"Authorization": "Bearer " + os.environ["GYRO_TOKEN"]}
r = requests.post("https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/ips", headers=h, json={"count": 1}, timeout=60)
r.raise_for_status()
print(r.json()["data"])
```
```js
const res = await fetch("https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/ips", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.GYRO_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({"count": 1}),
});
const { data, error } = await res.json();
if (!res.ok) throw new Error(`${error.code}: ${error.message}`);
```


## DELETE /cloud/servers/{id}/ips/{ip}

**Release an additional IPv4 address** · operationId `removeServerIp` · scope `cloud_write` · OpenAPI fragment: https://www.gyrohosting.com/developers/spec/ops/removeServerIp.json

**Minimum charge:** each added IP is billed for at least 6 hours (`pricing.minimum_hours`): releasing it earlier still bills the minimum (debited at release), and taking the same address again starts a new minimum. At most `adds_per_hour` addresses (default 10) can be added to a server per 60 minutes. The address is removed from the server and returns to the pool (getting the same address back is not guaranteed); billing stops at release (the minimum still applies). Needs `confirm=true`.


### Parameters

| Field | in | Type | Description |
|---|---|---|---|
| `id` (required) | path | integer | Server id (tr-ist-1) |
| `ip` (required) | path | string |  |
| `confirm` (required) | query | boolean |  |

### Responses

- **200**: OK
- **404**: Not found — also returned for objects owned by someone else
- **409**: not_actionable (suspended / busy)
- **422**: Validation or business rule failure (`confirm_required`, `invalid_image`, `tool_action_failed` ...)
- **501**: not_supported (not a tr-ist-1 Gyro Compute server)

### Examples

```bash
curl -s -X DELETE 'https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/ips/1' \
  -H "Authorization: Bearer $GYRO_TOKEN"
```
```bash
gyro server ip remove 12345
```
```hcl
# resource gyro_server_ip: https://registry.terraform.io/providers/gyro-hosting/gyro/latest/docs/resources/server_ip
resource "gyro_server_ip" "extra" {
  count     = 2
  server_id = gyro_server.web.id
}

output "extra_ips" {
  value = gyro_server_ip.extra[*].ip
}
```
```python
import os, uuid, requests

h = {"Authorization": "Bearer " + os.environ["GYRO_TOKEN"]}
r = requests.delete("https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/ips/1", headers=h, timeout=60)
r.raise_for_status()
print(r.json()["data"])
```
```js
const res = await fetch("https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/ips/1", {
  method: "DELETE",
  headers: {
    "Authorization": `Bearer ${process.env.GYRO_TOKEN}`,
  },
});
const { data, error } = await res.json();
if (!res.ok) throw new Error(`${error.code}: ${error.message}`);
```
