# Change a floating IP's DDoS protection

> Choose how DDoS Shield filters traffic to a floating IP, set its rate limits and add rules for ports and sources.

Source: https://www.coritan.com/docs/floating-ips/shield-settings/

In the dashboard:

- /dashboard/networking/ips/…/shield: https://www.coritan.com/dashboard/networking/ips

DDoS Shield filters the traffic to every floating IP on your account, attached or not. Each floating IP starts on the *platform default profile*, the settings we apply to every address. On the **Shield** tab you can give an address its own profile, then choose how strictly we filter it, set its rate limits and add rules that allow, drop or rate limit traffic by protocol, source and port.

[How DDoS Shield works](/docs/ddos-shield/how-ddos-shield-works/) explains the filtering itself.

## Before you begin

- The floating IP must be on your account and not cancelled.
- Know the protocols and ports your services use, such as TCP `443` for a website, TCP `22` for SSH or TCP `25565` for a Minecraft Java server. A rule that drops them cuts your service off.
- Once you customise an address, it keeps a profile of its own, and this tab has no control that returns it to the platform default. Binding the address to a [custom profile](/docs/ddos-shield/custom-profiles/) and then unbinding it does return it to the platform default.
- A subnet has one profile for all of its hosts.

## See how the address is protected

1. In the [dashboard](https://www.coritan.com/dashboard/networking), go to **Floating IPs**, open the address and select the **Shield** tab.
2. Read the profile card and the **Rules** card under it.

An address on the default shows the **Platform default profile** card, which lists its **Protection mode**, what happens **When no rule matches**, how it treats **Established connections**, and its rate limits. You cannot change the default itself.

An address with its own profile shows the profile's name, such as `Customer IP 214`, with the badge `Custom`, and a form in place of the list.

## Give the address its own profile

1. On the **Platform default profile** card, select **Customise**.

A message confirms `This address now has its own protection profile.` Adding a rule, as [Add a rule](#add-a-rule) describes, does the same.

The new profile starts with:

- **Protection mode** set to **Custom**
- **When no rule matches** set to **Allow**
- **Pass established connections** ticked
- the rate limits in [Rate limits](#rate-limits)
- no rules

## Change the profile

1. On the profile card, change any of the fields that the sections below describe.
2. Select **Save profile**.

A message confirms `Protection profile saved.`, and the card footer shows when the profile last changed. As the card says, the change reaches our filtering within a minute.

### Protection modes

**Standard**
: We filter the address with the platform's own checks and rate limits. Your rules and **When no rule matches** still apply. The rate limits on your profile do not.

**Custom**
: The same as **Standard**, with the rate limits on your profile in place of the platform's.

**Passthrough**
: We skip our checks, your rate limits and your rules. We still drop packets that are malformed or could not be real, such as a packet that claims to come from the address it is sent to.

> [!WARNING]
> With **Passthrough**, an attack on the address reaches your instance or server in full. Use it only for as long as you need to.

In **Standard** and **Custom**, only TCP, UDP and ICMP reach the address. We drop every other protocol, such as GRE or ESP. We also drop UDP packets sent from the ports that reflection attacks use, such as `53` for DNS and `123` for NTP. Your rules cannot let these packets through. [How DDoS Shield works](/docs/ddos-shield/how-ddos-shield-works/#reflection-ports) lists the ports.

### When no rule matches

**Allow**
: Traffic gets through unless a rule drops it. This is the setting a new profile starts with.

**Drop**
: Only traffic that an **Allow** rule matches gets through.

**Pass established connections** matters only when **When no rule matches** is **Drop**. It lets through a TCP packet that belongs to a connection already open and is sent to port 1024 or above, with no **Allow** rule needed. This keeps replies to the connections your machine opens working. A rule that matches the packet still decides, and the rate limits still apply.

> [!IMPORTANT]
> Before you choose **Drop**, add an **Allow** rule for every port your services use. **Pass established connections** covers TCP only, so also add **Allow** rules for the UDP and ICMP replies your machine expects, such as an **ICMP** rule for ping.

### Rate limits

The rate limits apply only when **Protection mode** is **Custom**. Traffic over a limit is dropped.

| Field | Range | A new profile starts at | What it limits |
| --- | --- | --- | --- |
| **Packets per second per source** | 100–10,000,000 | 100,000 | Packets from one sender. |
| **Aggregate packets per second** | 10,000–100,000,000 | 10,000,000 | All traffic to the address together. |
| **SYN per second per source** | 100–10,000,000 | 10,000 | New TCP connections from one sender. |
| **ICMP per second per source** | 10–1,000,000 | 5,000 | Pings and other ICMP from one sender. |

## Add a rule

1. On the **Rules** card, select **Add rule…**.
2. Fill in the **Add rule** form. Leave a field empty to match anything.
   - **Name**: a name to know the rule by, such as `ssh-office`.
   - **Action**: **Drop**, **Allow** or **Rate limit**. For **Rate limit**, also enter the **Limit (packets per second)** that each sender may send.
   - **Protocol**: **Any protocol**, **TCP**, **UDP** or **ICMP**.
   - **Source prefix**: the senders the rule applies to, such as `198.51.100.0/24`.
   - **Destination prefix**: leave it empty to match the whole floating IP. On a subnet, enter a host, such as `203.0.113.18/32`, to aim the rule at that host.
   - **Source ports** and **Destination ports**: for one port, fill in the first box. For a range, fill in both, such as `27015` and `27020`.
   - **Notes**: why the rule exists.
3. Select **Add rule**.

> [!IMPORTANT]
> Write every prefix with its length, such as `198.51.100.7/32` for a single sender. A prefix without a length, or a port in the second box alone, does not limit the rule, so it matches every sender or every port.

A message confirms the rule, such as `Rule "ssh-office" added.` You cannot edit a rule. To change one, add the new version and delete the old one.

## How rules are applied

Traffic to the address passes our packet checks and the rate limits first. Your rules then decide what happens to the rest:

- When one rule matches a packet, its action applies.
- When several rules match, the most specific rule decides. A rule is more specific when it names more about the packet: a protocol, a narrower prefix, or a single port in place of a range.
- When two matching rules are equally specific, **Drop** wins.
- When no rule matches, **When no rule matches** decides.

The order in which you add rules does not matter. A rule that matches everything, which the table shows as `Every packet`, only takes effect as **Drop**, so give an **Allow** or **Rate limit** rule at least one field.

A **Rate limit** rule counts each sender on its own. It lets a sender through at up to the limit, with short bursts of up to twice the limit, and drops the rest.

These rule sets cover common needs:

| Goal | Rules |
| --- | --- |
| Allow SSH from your office only | **Drop**, **TCP**, destination port `22`. Then **Allow**, **TCP**, source prefix `198.51.100.0/24`, destination port `22`. The second rule is more specific, so it wins for your office. |
| Block one sender | **Drop**, **Any protocol**, source prefix `198.51.100.7/32`. |
| Limit each sender on a Bedrock server | **Rate limit**, **UDP**, destination port `19132`, with a limit such as `2000`. |

## Delete a rule

1. On the **Rules** card, select **Delete…** on the rule's row.
2. Type the rule's name and select **Delete rule**.

Traffic that the rule matched then meets your other rules and **When no rule matches**.

## Result

The profile card shows your profile's settings. Its badge reads `Custom`, followed by `· Standard` or `· Passthrough` when you chose one of those modes. The **Rules** table lists each rule with its **Action**, what it **Matches**, such as `TCP · from 198.51.100.0/24 · to port 22`, and its **State**.

Attacks on the address show on the **Events** tab of [DDoS Shield](https://www.coritan.com/dashboard/ddos/events), as [Read attack events](/docs/ddos-shield/attack-events/) describes.

## Troubleshooting

Your service stopped answering after a change
: A rule, or **When no rule matches** set to **Drop**, drops traffic the service needs. Add an **Allow** rule for its protocol and port, or set **When no rule matches** back to **Allow**.

A rule drops far more than you meant
: The rule has a prefix without a length, or a port in the second box alone, so it matches everything. Delete it and add it again with the full prefix, such as `198.51.100.7/32`, and the port in the first box.

An **Allow** rule has no effect
: The rule has no fields, or a more specific **Drop** rule matches the same traffic. Give the rule a protocol, prefix or port that is at least as specific as the **Drop** rule.

Your rate limits have no effect
: **Protection mode** is **Standard**, which uses the platform's own limits. Set it to **Custom**.

A GRE or IPsec tunnel to the address does not connect
: In **Standard** and **Custom** we drop GRE and ESP, and UDP from ports `500` and `4500`, which IPsec uses. Use a tunnel that runs over UDP on another port, such as WireGuard.

DNS lookups or time sync on the machine time out
: DNS and NTP servers answer from UDP ports `53` and `123`. In **Standard** and **Custom** we drop those packets when they are sent to this address, and a rule cannot let them through. [Contact support](/docs/support/conversations/) if a service on the address needs one of these ports.

There is no **Delete…** button on the rules
: The address is on the platform default profile, and its rules belong to the platform. Select **Customise** to give the address a profile of its own.

`Could not save the protection profile` or `Could not add the rule`
: We refused the change. The message beside it gives the reason. Correct the field it names and try again.

## Related

- [How DDoS Shield works](/docs/ddos-shield/how-ddos-shield-works/)
- [Read attack events](/docs/ddos-shield/attack-events/)
- [How subnets work](/docs/floating-ips/subnets/)
- [Attach and detach a floating IP](/docs/floating-ips/attach-and-detach/)

## With the API

The requests take the floating IP's service ID in the path.

`GET /api/v1/client/shield/subjects/{ip_service_id}/profile` returns the profile that filters the address, with its rules:

```bash
curl https://api.coritan.com/api/v1/client/shield/subjects/214/profile \
  -H "Authorization: Bearer $CORITAN_TOKEN"
```

```json
{
  "mode": "custom",
  "editable": true,
  "profile": {
    "id": 57,
    "name": "Customer IP 214",
    "protection_mode": "custom",
    "default_action": "allow",
    "established_passthrough": true,
    "rate_limits": {"per_source_pps": 100000, "aggregate_pps": 10000000, "syn_pps_per_source": 10000, "icmp_pps_per_source": 5000},
    "updated_at": "2026-09-25T10:00:00"
  },
  "rules": [
    {"id": 311, "name": "ssh-office", "enabled": 1, "action": "allow", "protocol": 6, "src_prefix": "198.51.100.0/24", "dst_prefix": null, "dst_port_min": 22, "dst_port_max": 22, "rate_limit_pps": null}
  ]
}
```

The example leaves out fields the dashboard does not show. Until the address has its own profile, `mode` is `platform_default`, `editable` is `false`, and `profile` and `rules` describe the platform default profile.

`PATCH /api/v1/client/shield/subjects/{ip_service_id}/profile` gives the address its own profile, when it has none, and changes it:

```bash
curl -X PATCH https://api.coritan.com/api/v1/client/shield/subjects/214/profile \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"default_action": "deny", "rate_limits": {"per_source_pps": 50000}}'
```

| Field | Meaning |
| --- | --- |
| `protection_mode` | `standard`, `custom` or `passthrough`. |
| `default_action` | `allow`, or `deny` for **Drop**. |
| `established_passthrough` | `true` or `false`. |
| `rate_limits` | Any of `per_source_pps`, `aggregate_pps`, `syn_pps_per_source` and `icmp_pps_per_source`, within the ranges in [Rate limits](#rate-limits). A limit you leave out keeps its value. |

Every field is optional. Send `{}` to give the address its own profile and change nothing. The response has the same shape as `GET`. A `protection_mode` or `default_action` outside its words answers `422` with `protection_mode must be standard|custom|passthrough` or `default_action must be allow|deny`. A floating IP that is not on your account, or is cancelled, answers `404` with a message that starts `IP service`.

`POST /api/v1/client/shield/subjects/{ip_service_id}/rules` adds a rule, and gives the address its own profile first when it has none:

```bash
curl -X POST https://api.coritan.com/api/v1/client/shield/subjects/214/rules \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "ssh-office", "action": "allow", "protocol": 6, "src_prefix": "198.51.100.0/24", "dst_port_min": 22, "dst_port_max": 22}'
```

| Field | Meaning |
| --- | --- |
| `name` | 1–191 characters. |
| `action` | `deny` (the default), `allow` or `rate_limit`. |
| `protocol` | The IP protocol number: `6` for TCP, `17` for UDP, `1` for ICMP. Leave it out to match any protocol. |
| `src_prefix`, `dst_prefix` | A prefix with its length, such as `198.51.100.0/24`. |
| `src_port_min`, `src_port_max`, `dst_port_min`, `dst_port_max` | A port range. For one port, send the same number as both the minimum and the maximum. |
| `rate_limit_pps` | For `rate_limit`, the packets per second each sender may send. |
| `enabled` | `false` saves the rule without applying it, and the dashboard shows it as `Off`. It defaults to `true`. |
| `notes` | Free text. |

The API also takes matches that the dashboard does not offer: `tcp_flags_mask` with `tcp_flags_value`, `packet_len_min` and `packet_len_max`, `ttl_min` and `ttl_max`, and `icmp_type` with `icmp_code`.

The response is the new rule with its `id`. An `action` outside its words answers `422` with `action must be allow|deny|rate_limit`. The API does not check the other fields, so check them yourself. A prefix without a length matches every address, and a `*_port_max` without its `*_port_min` matches every port. A `rate_limit` rule without `rate_limit_pps` allows 1,000 packets per second from each sender.

`DELETE /api/v1/client/shield/subjects/{ip_service_id}/rules/{rule_id}` deletes a rule and answers `{"status": "deleted"}`:

```bash
curl -X DELETE https://api.coritan.com/api/v1/client/shield/subjects/214/rules/311 \
  -H "Authorization: Bearer $CORITAN_TOKEN"
```

A rule of another profile answers `403` with `Rule does not belong to this subject profile`. An address without a profile of its own answers `404` with a message that starts `Custom Shield profile for IP`.

The [DDoS Shield API reference](/docs/api/reference/client/shield/#op-patch-api-v1-client-shield-subjects-ip-service-id-profile) lists every field.

## API

- `GET /api/v1/client/shield/subjects/{ip_service_id}/profile`: The profile scrubbing this IP: the platform default, or its custom one (https://www.coritan.com/docs/api/reference/client/shield/#op-get-api-v1-client-shield-subjects-ip-service-id-profile)
- `PATCH /api/v1/client/shield/subjects/{ip_service_id}/profile`: Ensure custom profile (https://www.coritan.com/docs/api/reference/client/shield/#op-patch-api-v1-client-shield-subjects-ip-service-id-profile)
- `POST /api/v1/client/shield/subjects/{ip_service_id}/rules`: Create subject rule (https://www.coritan.com/docs/api/reference/client/shield/#op-post-api-v1-client-shield-subjects-ip-service-id-rules)
- `DELETE /api/v1/client/shield/subjects/{ip_service_id}/rules/{rule_id}`: Delete subject rule (https://www.coritan.com/docs/api/reference/client/shield/#op-delete-api-v1-client-shield-subjects-ip-service-id-rules-rule-id)
