# SafeDNS Shield

# Overview

<span class="">SafeDNS Shield is an on-premises web filtering and security solution that operates as a DNS proxy. It processes every DNS query to identify the requesting user, evaluates the queried domain against that user’s filtering policy, and then allows or blocks the request.</span>

<span class="">When a domain is blocked, the proxy resolves it to the IP address of a block page instead of returning the actual IP. The block page can be a custom corporate page hosted outside the solution, or the default block page built into SafeDNS Shield, which can also be customized.</span>

<span class="">If a domain is allowed, the proxy forwards the DNS request to the next server in the resolution chain. This server can be a local corporate DNS server, an ISP’s caching DNS resolver, or any public DNS service (for example, Google Public DNS or Cloudflare).</span>

<span class="">Because SafeDNS Shield inspects all DNS traffic, it enables comprehensive, per‑user traffic analysis. Every request is logged, providing access to detailed statistical information.</span>

# Architecture and deployment

### Components

[![image-1772786479925.png](https://docs.safedns.com/uploads/images/gallery/2026-03/scaled-1680-/MuD0Wr8fD6cCi4bA-image-1772786479925.png)](https://docs.safedns.com/uploads/images/gallery/2026-03/MuD0Wr8fD6cCi4bA-image-1772786479925.png)

<span class="">SafeDNS Shield is composed of the following components:</span>

- **<span class="">DNS Proxy Module</span>**  
    <span class="">The core filtering engine. It receives DNS requests from end users, identifies the requesting user, applies the configured filtering policy, and returns either the resolved IP address or the IP address of a block page.</span>
- **<span class="">Internal Database</span>**  
    <span class="">Stores all configuration and policy data: user identifiers (subnet, IP, port), filtering profiles, block pages, user groups, and their assignments.</span>
- <span class="">**Block pages**  
    HTTP/S pages served to the users instead of blocked websites. Can be hosted alongside Shield or on an external server.  
    </span>
- **<span class="">REST API</span>**  
    <span class="">Provides a management interface for administrators to update the Internal Database. It supports creation and modification of:</span>
    
    
    - <span class="">User identifiers (subnet, IP, port)</span>
    - <span class="">Filtering profiles (categories to block)</span>
    - <span class="">Block pages</span>
- **<span class="">Binary Log Parsing Module (StatsLoader)</span>**  
    <span class="">Processes the binary log files generated by the DNS Proxy. It parses the DNS query logs, extracts statistics, and sends them to the ClickHouse cluster for storage and analysis.</span>
- **<span class="">ClickHouse Cluster</span>**  
    <span class="">A distributed database for storing and analyzing DNS request statistics. The cluster is divided into shards, each containing multiple mirrored nodes for fault tolerance and high‑performance parallel reads and writes.</span>
    
    
    - **<span class="">Load Balancer</span>**  
        <span class="">Receives statistics data from StatsLoader and distributes it evenly across the ClickHouse cluster nodes.</span>
    - **<span class="">ZooKeeper</span>**  
        <span class="">Manages coordination and configuration of the ClickHouse cluster, ensuring data consistency and system reliability.</span>

<span class="">The DNS Proxy writes its binary query logs to a designated host path (</span>`HostPATH`<span class="">), from which StatsLoader reads them.</span>

**<span class="">External dependencies</span>**  
<span class="">The following elements are not part of SafeDNS Shield but are required for operation:</span>

- **<span class="">User</span>**<span class=""> – The end‑user device that sends DNS requests to SafeDNS Shield.</span>
- **<span class="">Caching DNS Server</span>**<span class=""> – A recursive resolver deployed on the organization’s network that performs upstream DNS resolution for allowed queries.</span>

### Deployment options

SafeDNS Shield supports multiple deployment options to accommodate different network topologies. This section describes the most common scenarios.

##### For ISPs

##### **![](https://docs.safedns.com/uploads/images/gallery/2024-10/qNQmeYymeTxr15Xl-image-1728560145793.png)**

This deployment option is used in ISP networks, where NAT separates end users from the on-premises DNS infrastructure, making it impossible to identify them solely by their individual IP addresses.

<div class="pointer-container" id="bkmrk-%C2%A0"><div class="pointer anim is-page-editable"><svg class="svg-icon" data-icon="link" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg><div class="input-group inline block"> <button class="button outline icon" data-clipboard-target="#pointer-url" title="Copy Link" type="button"><svg class="svg-icon" data-icon="copy" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></button></div><svg class="svg-icon" data-icon="edit" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></div></div>##### For corporate clients  


[![image-1772786346085.png](https://docs.safedns.com/uploads/images/gallery/2026-03/scaled-1680-/eNEcaAFBnndiMMt5-image-1772786346085.png)](https://docs.safedns.com/uploads/images/gallery/2026-03/eNEcaAFBnndiMMt5-image-1772786346085.png)

or

[![image-1772786395390.png](https://docs.safedns.com/uploads/images/gallery/2026-03/scaled-1680-/wUXsLWAApQ8PeBDb-image-1772786395390.png)](https://docs.safedns.com/uploads/images/gallery/2026-03/wUXsLWAApQ8PeBDb-image-1772786395390.png)

This deployment option is used in corporate networks where end users can be identified by their individual IP addresses at the point where SafeDNS Shield is deployed. Depending on whether the organization has its own caching DNS server, requests are forwarded to that server or to an external resolver, such as an ISP’s DNS or a public DNS service (e.g., 1.1.1.1 or 8.8.8.8).

### <span class="">User Identification</span>

**<span class="">User Identification</span>**

<span class="">To apply filtering policies and to separate statistics on a per‑user basis, SafeDNS Shield must identify each end user. Identification is based on the source address of the DNS request and can be configured using one of the following methods:</span>

- **<span class="">IP address</span>**<span class=""> – Use when each user has a unique IP address.</span>
- **<span class="">IP subnet</span>**<span class=""> – Use when per‑user granularity is not required and all users in a subnet can share the same policy.</span>
- **<span class="">IP:port</span>**<span class=""> – Use when multiple users share a single IP address (for example, behind NAT44 or CGNAT). The source port distinguishes individual users.</span>
- **<span class="">IP:port range</span>**<span class=""> – Use when users can be identified by a range of source ports on a shared IP address.</span>

<span class="">The appropriate method depends on the network topology and the level of user separation required.</span>

# Setup and requirements

### <span class="">Product setup and support</span>

##### <span class="">Custom Local Deployment</span>

<span class="">Setup, maintenance, and support for an on-premises deployment are managed entirely by SafeDNS specialists, establishing a clear division of responsibilities. The client provides the required hardware and full remote access, after which SafeDNS performs the complete turnkey installation.</span>

<span class="">Following deployment, SafeDNS specialists work with the client to configure the initial filtering rules and provide training to enable the client’s staff to make future adjustments independently. A dedicated support line is available for clients using on-premises solutions.</span>

##### <span class="">VM Deployment via ISO Image</span>

<span class="">As an alternative to a physical server installation, SafeDNS Shield can be deployed as a virtual appliance by mounting the provided ISO image in a virtual machine. This method streamlines deployment in environments that rely on virtualization infrastructure.</span>

### <span class="">System requirements</span>

<span class="">The following specifications apply to a server running the SafeDNS Shield components. All deployments require Debian 12 (x86‑64).</span>

##### <span class="">DNS Proxy Module</span>

<span class="">Choose a configuration based on the expected peak query load.</span>

<span class="">CPU: Intel 12th‑generation or later, Intel Xeon Silver/Gold, or equivalent AMD Ryzen/Epyc.</span>

<div class="ds-scroll-area ds-scroll-area--show-on-focus-within _1210dd7 c03cafe9" id="bkmrk-queries-per-second-%28"><table><thead><tr><th><span class="">Queries per second (QPS)</span></th><th><span class="">CPU Cores</span></th><th><span class="">RAM</span></th><th><span class="">Storage</span></th><th><span class="">Network</span></th></tr></thead><tbody><tr><td><span class="">Up to 1,000</span></td><td><span class="">4</span></td><td><span class="">8 GB</span></td><td><span class="">200 GB NVMe</span></td><td><span class="">1 Gbps</span></td></tr><tr><td><span class="">Up to 15,000</span></td><td><span class="">12</span></td><td><span class="">16 GB</span></td><td><span class="">512 GB SSD (RAID 1)</span></td><td><span class="">1 Gbps</span></td></tr><tr><td><span class="">Up to 310,000</span></td><td><span class="">64</span></td><td><span class="">128 GB</span></td><td><span class="">2 TB SSD/NVMe (RAID 1)</span></td><td><span class="">1 Gbps</span></td></tr><tr><td><span class="">Up to 2,000,000</span></td><td><span class="">128</span></td><td><span class="">2 TB</span></td><td><span class="">16 TB SSD/NVMe (RAID 1)</span></td><td><span class="">25 Gbps</span></td></tr></tbody></table>

</div>##### <span class="">ClickHouse Cluster (Statistics Storage)</span>

<span class="">The ClickHouse cluster stores and analyzes DNS request logs. A single node meets the following minimum:</span>

- <span class="">CPU: **6** cores (x86‑64)</span>
- <span class="">RAM: **16** GB</span>
- <span class="">Storage: **500** GB NVMe</span>
    - <span class="">Expandable up to **6** TB depending on traffic volume and retention needs</span>

*<span class="">Example configuration for **75,000** QPS and one year of log retention:</span>*

- <span class="">**4** ClickHouse data nodes</span>
    - <span class="">CPU: **6** cores</span>
    - <span class="">RAM: **16** GB</span>
    - <span class="">Storage: **6** TB NVMe</span>
- <span class="">**3** ClickHouse Keeper nodes</span><span class=""> (coordination service)</span>
    - <span class="">CPU: **2** cores</span>
    - <span class="">RAM: **4** GB</span>
    - <span class="">Storage: **60** GB SSD</span>

<span class="">We recommend a minimum cluster of 4 data servers arranged as 2 shards × 2 replicas. This provides parallel read/write operations and redundancy. A load balancer distributes incoming statistics across the nodes.</span>

<span class="">For lower traffic volumes, a standalone ClickHouse server can be deployed without ClickHouse Keeper, eliminating the need for the coordination layer.</span>

# Miscellaneous

### Working with statistics

<span class="">The DNS Proxy generates binary logs, which are stored directly on the SafeDNS Shield server. A dedicated parsing module processes these logs and exports the resulting data to an external DBMS for analysis and report generation. The module includes a connector for ClickHouse, which provides the best performance for this data type, but logs can also be exported to other databases if required.</span>

<span class="">The local binary log storage acts as a buffer: if the connection to ClickHouse is temporarily lost, logs generated during the outage are retained on disk and automatically exported once connectivity is restored. No data is lost during short interruptions, provided the local storage on the Shield server does not become completely full.</span>

<span class="">Although the statistics module is not essential for the core filtering functionality, it is indispensable for assessing system performance and investigating incidents effectively.</span>

### Note on HTTPS block pages

<span class="">To display the built‑in block page for HTTPS requests, the SafeDNS root certificate must be added to the trusted certificate store on every end user device. Without the certificate, web browsers cannot validate the block page’s TLS certificate; instead of the block page, users will see a TLS/SSL error. Access to the requested resource will still be denied.</span>  
<span class="">Displaying the block page over HTTP does not require the certificate.</span>  
<span class="">If an externally hosted block page is used, certificate requirements depend on your own hosting configuration.</span>

# REST API overview

<span class="">All administration and configuration of SafeDNS Shield is performed through the REST API. The API listens on port 8080 of the same IP address that handles DNS queries. By default, access is restricted to a set of whitelisted IP addresses specified during deployment.</span>

#### <span class="">Initial Configuration Example</span>

<span class="">The following example demonstrates the initial configuration workflow. Send the following request:</span>

<div class="pointer-container" id="bkmrk-%C2%A0"><div class="pointer anim is-page-editable"><svg class="svg-icon" data-icon="link" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg><div class="input-group inline block"> <button class="button outline icon" data-clipboard-target="#pointer-url" title="Copy Link" type="button"><svg class="svg-icon" data-icon="copy" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></button></div><svg class="svg-icon" data-icon="edit" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></div></div>- Type: POST
- URL: `<domain>/init/`
- Data:

```
{
    "profiles": [
        {
            "profile": {
                "id": 1,
                "page_id": 1
            },
            "cat_ids": [3, 4, 12],
            "app_ids": [1, 12, 93]
        }
    ],
    "blockpages": [
        {
            "id": 1,
            "type": 0
        },
        {
            "id": 2,
            "type": 1
        }
    ],
    "bw_lists": [
       {
            "profile_id": 1,
            "type": "deny",
            "domains": [
                "example1.com",
                "example2.com",
                "example3.com"
            ]
        }
    ],
    "nets": [
        {
            "ip": "100.100.100.100",
            "profile_id": 1,
            "prefix_len": 32
        },
        {
            "ip": "100.110.110.0",
            "profile_id": 1,
            "prefix_len": 24
        },
        {
            "ip": "100.120.0.0",
            "profile_id": 1,
            "prefix_len": 16
        }
    ],
    "nets6": [],
    "napts": []
}
```

<span class="">The initialization query defines the full configuration applied to SafeDNS Shield. The following settings are processed in sequence:</span>

1. **<span class="">Filtering profile and block page</span>**<span class=""> – A filtering profile (ID=1) and a block page (ID=1) are created.</span>
2. **<span class="">Blocked categories</span>**<span class=""> – Three DNS categories are blocked for the profile: malware, phishing, and botnets.</span>
3. **<span class="">Blocked applications</span>**<span class=""> – Three AppBlocker categories are blocked: Slack, AnyDesk, and Netflix.</span>
4. **<span class="">Block pages</span>**<span class=""> – Two block pages of different types are created:</span>
    
    
    - <span class="">Type 0 – displays the blocked domain name.</span>
    - <span class="">Type 1 – does not display the blocked domain name.</span>
5. **<span class="">Blacklist</span>**<span class=""> – Three domains are added to the blacklist for filtering profile 1.</span>
6. **<span class="">IP assignment</span>**<span class=""> – The profile is assigned one specific IP address and two subnets (/16 and /24). DNS requests from these sources are filtered according to the profile’s policy.</span>
7. **<span class="">IPv6 and NAT‑port identification</span>**<span class=""> – The </span>`nets6`<span class=""> (IPv6) and </span>`napts`<span class=""> (NAT port‑based identification) sections are included but left empty. These fields must be present in the request even if not used, to trigger the creation of the initial configuration.</span>

<span class="">Once the request is sent and a successful response (HTTP status </span>`204`<span class="">) is received, the initial configuration is complete. All subsequent DNS traffic processed by the server is handled according to the specified rules.</span>

##### Modifying Filtering Categories

<span class="">To modify the filtering categories for an existing profile, you must update the entire list of categories assigned to that profile. Adding new categories requires sending the full set (both current and new categories) in a single request.</span>

<span class="">For example, the initial configuration created profile </span>`id=1`<span class=""> with three blocked categories: malware, phishing, and botnets. To add Cryptojacking, DGA, and Ransomware, the request must include all six categories:</span>

<div class="pointer-container" id="bkmrk-%C2%A0-0"><div class="pointer anim is-page-editable"><svg class="svg-icon" data-icon="link" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg><div class="input-group inline block"> <button class="button outline icon" data-clipboard-target="#pointer-url" title="Copy Link" type="button"><svg class="svg-icon" data-icon="copy" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></button></div><svg class="svg-icon" data-icon="edit" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></div></div>- Type: PATCH
- URL: `<domain>/profiles/<strong>1</strong>/`
- Data:

```
{
  "cat_ids": [3, 4, 12, 66, 70, 71],
  "app_ids": [1, 12, 93],
  "profile": {
    "page_id": 1
  }
}
```

In this request, the profile ID is specified directly in the URL. The request body contains the updated list of categories (original three and three new) while the AppBlocker categories and block page remain unchanged.

##### Adding a Domain to the Allowlist

<span class="">To exempt a specific domain from category-based blocking, add it to the allowlist of the relevant filtering profile. For profile </span>`id=1`<span class="">, send the following request:</span>

<div class="pointer-container" id="bkmrk-%C2%A0-1"><div class="pointer anim is-page-editable"><svg class="svg-icon" data-icon="link" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg><div class="input-group inline block"> <button class="button outline icon" data-clipboard-target="#pointer-url" title="Copy Link" type="button"><svg class="svg-icon" data-icon="copy" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></button></div><svg class="svg-icon" data-icon="edit" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></div></div>- Type: POST
- URL: `<domain>/profile/<strong>1</strong>/bw_list`
- Data:

```
{
  "type": "allow",
  "domain": "example4.com"
}
```

<span class="">This adds the domain to the allowlist, giving it priority over category-based blocking.</span>

##### <span class="">Adding Domains to the Denylist</span>

<span class="">To block specific domains that are not covered by the configured categories, add them directly to the denylist for the filtering profile. The following request adds domains in a batch operation for profile </span>`id=1`<span class="">:</span>

<div class="pointer-container" id="bkmrk-%C2%A0-2"><div class="pointer anim is-page-editable"><svg class="svg-icon" data-icon="link" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg><div class="input-group inline block"> <button class="button outline icon" data-clipboard-target="#pointer-url" title="Copy Link" type="button"><svg class="svg-icon" data-icon="copy" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></button></div><svg class="svg-icon" data-icon="edit" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></div></div>- Type: POST
- URL: `<domain>/profile/<strong>1</strong>/bw_list/batch`
- Data:

```
{
  "type": "deny",
  "domains": ["example5.com", "example6.com", "example7.com", "example8.com", "example9.com"]
}
```

##### <span class="">Adding a Network or IP Address for Filtering</span>

<span class="">To assign a new IP address or subnet to a filtering profile, send the following request. The example adds a single IP address by specifying a </span>`/32`<span class=""> network prefix for profile </span>`id=1`<span class="">:</span>

<div class="pointer-container" id="bkmrk-%C2%A0-3"><div class="pointer anim is-page-editable"><svg class="svg-icon" data-icon="link" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg><div class="input-group inline block"> <button class="button outline icon" data-clipboard-target="#pointer-url" title="Copy Link" type="button"><svg class="svg-icon" data-icon="copy" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></button></div><svg class="svg-icon" data-icon="edit" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></div></div>- Type: POST
- URL: `<domain>/net/`
- Data:

```
{
    "ip": "100.100.100.101",
    "profile_id": 1,
    "prefix_len": 32
}
```

<span class="">To add an entire subnet, adjust the prefix length accordingly. For instance, a </span>`/24`<span class=""> subnet would be specified as:</span>

```
{
    "ip": "100.100.101.0",
    "profile_id": 1,
    "prefix_len": 24
}
```

##### <span class="">Removing an IP Address from Filtering</span>

<span class="">To remove a previously assigned IP address or subnet from a filtering profile, send the following request:</span>

- Type: DELETE
- URL: `<domain>/net/<strong>1684300901</strong>`
- Data: None

<span class="">This request has no body. The IP address must be provided in decimal format in the URL. Use the exact address originally submitted, without the mask - for example, </span>`100.100.100.101`<span class=""> or </span>`100.100.101.0`<span class=""> from the earlier examples. You can convert an IP address to decimal format using a tool like [this one](https://www.browserling.com/tools/ip-to-dec).</span>

##### Modifying the Filtering Profile for a Specific IP

<span class="">To change the filtering profile assigned to an existing IP address or subnet, send the following request. The IP address must be provided in decimal format in the URL. This example reassigns the address </span>`100.100.101.0`<span class=""> (originally a </span>`/24`<span class=""> subnet) from profile </span>`id=1`<span class=""> to profile </span>`id=2`<span class="">:</span>

<div class="pointer-container" id="bkmrk-%C2%A0-4"><div class="pointer anim is-page-editable"><svg class="svg-icon" data-icon="link" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg><div class="input-group inline block"> <button class="button outline icon" data-clipboard-target="#pointer-url" title="Copy Link" type="button"><svg class="svg-icon" data-icon="copy" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></button></div><svg class="svg-icon" data-icon="edit" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></div></div>- Type: PATCH
- URL: `<domain>/net/<strong>1684301056</strong>`
- Data:

```
{
    "ip": "100.100.101.0",
    "profile_id": 2,
    "prefix_len": 24
}
```

<span class="">To change the network prefix (for example, from </span>`/24`<span class=""> to </span>`/16`<span class="">), you must delete the existing record and add a new one with the correct network address. In this case, you would delete </span>`100.100.101.0`<span class=""> and add </span>`100.100.0.0`<span class=""> with the </span>`/16`<span class=""> prefix.</span>

##### Creating a New Filtering Profile

Before an IP can be reassigned to a different profile, that profile must exist. The following request creates a new filtering profile:

<div class="pointer-container" id="bkmrk-%C2%A0-5"><div class="pointer anim is-page-editable"><svg class="svg-icon" data-icon="link" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg><div class="input-group inline block"> <button class="button outline icon" data-clipboard-target="#pointer-url" title="Copy Link" type="button"><svg class="svg-icon" data-icon="copy" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></button></div><svg class="svg-icon" data-icon="edit" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></div></div>- Type: POST
- URL: `<domain>/profiles/`
- Data:

```
<br></br><br></br>```
{
    "profile": {
        "id": 2,
        "page_id": 1
    },
    "cat_ids": [3, 4, 12, 66, 70, 71, 13],
    "app_ids": [1, 12, 93]
}
```
```

<span class="">This creates profile </span>`id=2`<span class="">, configured with the same block page type and the same categories and AppBlocker settings as profile </span>`id=1`<span class="">, with the addition of the "Adult Related" category.</span>

# REST API reference

### User data methods

<div class="pointer-container" id="bkmrk-%C2%A0-6"><div class="pointer anim is-page-editable"><svg class="svg-icon" data-icon="link" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg><div class="input-group inline block"> <button class="button outline icon" data-clipboard-target="#pointer-url" title="Copy Link" type="button"><svg class="svg-icon" data-icon="copy" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></button></div><svg class="svg-icon" data-icon="edit" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></div></div>##### Initialize user data database (batch data creation)

- Type: POST
- URL: `<domain>/init/`
- Data: ```
    {
        'profiles': [
            {
                'cat_ids': [<cat_id>,],
                'app_ids': [<app_id>,],
                'profile': {
                    'page_id': <page_id>,
                    'id': <id>
                }
            }, ...
        ],
        'nets': [{'ip': <ipv4>, 'profile_id': <profile_id>, 'prefix_len': <prefix_len4>}, ...],
        'nets6': [{'ip': <ipv6>, 'profile_id': <profile_id>, 'prefix_len': <prefix_len6>}, ...],
        'blockpages': [{'id': <page_id>, 'type': <blockpage_type>}, ...],
        'napts': [
            {
                'ip': <ipv4>,
                "profile_id": <profile_id>,
                "lower_port_bound": <lower_port_bound>,
                "upper_port_bound": <upper_port_bound>
            },
        ]
    }
    ```
- Result: 204 No body

### Profile methods

<div class="pointer-container" id="bkmrk-%C2%A0-7"><div class="pointer anim is-page-editable"><svg class="svg-icon" data-icon="link" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg><div class="input-group inline block"> <button class="button outline icon" data-clipboard-target="#pointer-url" title="Copy Link" type="button"><svg class="svg-icon" data-icon="copy" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></button></div><svg class="svg-icon" data-icon="edit" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></div></div>##### Fetch all profiles

- Type: GET
- URL: `<domain>/profiles`
- Result: 200 OK

##### Add a profile

- Type: POST
- URL: `<domain>/profiles`
- Data: ```
    {
        "profile": {
            "id": int,
            "page_id": int
        },
        "cat_ids": [int, ],
        "app_ids": [int, ],
    }
    ```
- Result: 201 Created

##### Fetch a specific profile  


- Type: GET
- URL: `<domain>/profiles/<id>`
- Result: 200 OK

##### Update a specific profile

- Type: PATCH
- URL: `<domain>/profiles`
- Data: ```
    {
      "app_ids": [int, ],
      "cat_ids": [int, ],
      "profile": {
        "plan_id": int,
        "provider_id": int,
        "white_list_only": bool,
        "hide_block_reason": bool,
        "empty_dns_answer": bool,
        "page_id": int,
        "tls": bool
      }
    }
    ```
- Result: 200 OK

### Blockpage methods

<div class="pointer-container" id="bkmrk-%C2%A0-8"><div class="pointer anim is-page-editable"><svg class="svg-icon" data-icon="link" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg><div class="input-group inline block"> <button class="button outline icon" data-clipboard-target="#pointer-url" title="Copy Link" type="button"><svg class="svg-icon" data-icon="copy" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></button></div><svg class="svg-icon" data-icon="edit" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></div></div>##### Get all blockpages  


- Type: GET
- URL: `<domain>/blockpage`
- Result: 200 OK

##### Create a blockpage  


- Type: POST
- URL: `<domain>/blockpage`
- Data: ```
    {
      "type": int,
      "id": int
    }
    ```
- Result: 200 OK

##### Get a specific blockpage  


- Type: GET
- URL: `<domain>/blockpage/<page_id>`
- Result: 200 OK

##### Update a blockpage  


- Type: PATCH
- URL: `<domain>/blockpage/<page_id>`
- Data: ```
    {
      "type": int
    }
    ```
- Result: 200 OK

##### Delete a blockpage  


- Type: DELETE
- URL: `<domain>/blockpage/<page_id>`
- Result: 204 No Content, no body

### Lists methods

<div class="pointer-container" id="bkmrk-%C2%A0-9"><div class="pointer anim is-page-editable"><svg class="svg-icon" data-icon="link" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg><div class="input-group inline block"> <button class="button outline icon" data-clipboard-target="#pointer-url" title="Copy Link" type="button"><svg class="svg-icon" data-icon="copy" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></button></div><svg class="svg-icon" data-icon="edit" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></div></div>##### Create an allow- or denylist  


- Type: POST
- URL: `<domain>/profile/<profile_id>/bw_list`
- Data: ```
    {
      "type": "string", //"allow" or "deny" only
      "domains": ["string", "string", ]
    }
    ```
- Result: 201 Created

##### Create an allow- or denylist with multiple entries  


- Type: POST
- URL: `<domain>/profile/<profile_id>/bw_list/batch`
- Data: ```
    {
      "type": "string", //"allow" or "deny" only
      "domains": ["string", "string", ]
    }
    ```
- Result: 201 Created

##### Update a domain in an allow- or denylist  


- Type: PATCH
- URL: `<domain>/profile/<profile_id>/bw_list/<domain>`
- Data: ```
    {
      "type": "string", //"allow" or "deny" only
      "domain": "string",
      "profile_id": int
    }
    ```
- Result: 200 OK

Delete a domain from an allow- or denylist:

- Type: DELETE
- URL: `<domain>/profile/<profile_id>/bw_list/<domain>`
- Result: 204 No Content, no body

### IPv4 network methods

<div class="pointer-container" id="bkmrk-%C2%A0-10"><div class="pointer anim is-page-editable"><svg class="svg-icon" data-icon="link" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg><div class="input-group inline block"> <button class="button outline icon" data-clipboard-target="#pointer-url" title="Copy Link" type="button"><svg class="svg-icon" data-icon="copy" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></button></div><svg class="svg-icon" data-icon="edit" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></div></div>##### Create an IPv4 address entry  


- Type: POST
- URL: `<domain>/net`
- Data: ```
    {
      "ip": "string", //IPv4 address in canonical form
      "profile_id": int,
      "prefix_len": int
    }
    ```
- Result: 201 Created

##### Get an IPv4 address entry  


- Type: GET
- URL: `<domain>/net/<int_ip>`
- Result: 200 OK

##### Update an IPv4 address entry  


- Type: PATCH
- URL: `<domain>/net/<int_ip>`
- Data: ```
    {
      "ip": "string", //IPv4 address in canonical form
      "profile_id": int,
      "prefix_len": int
    }
    ```
- Result: 200 OK

##### Delete an IPv4 address  


- Type: DELETE
- URL: `<domain>/net/<int_ip>`
- Result: 204 No Content, no body

### IPv6 network methods

<div class="pointer-container" id="bkmrk-%C2%A0-11"><div class="pointer anim is-page-editable"><svg class="svg-icon" data-icon="link" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg><div class="input-group inline block"> <button class="button outline icon" data-clipboard-target="#pointer-url" title="Copy Link" type="button"><svg class="svg-icon" data-icon="copy" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></button></div><svg class="svg-icon" data-icon="edit" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></div></div>##### Create an IPv6 address entry  


- Type: POST
- URL: `<domain>/net6`
- Data: ```
    {
      "ip": "string", //IPv6 address in canonical form
      "prefix_len": int,
      "profile_id": int
    }
    ```
- Result: 201 Created

##### Get an IPv6 address entry  


- Type: GET
- URL: `<domain>/net6/<ipv6>`
- Result: Dictionary with IPv6 and profile\_id data

##### Update an IPv6 address entry  


- Type: PATCH
- URL: `<domain>/net6/<ipv6>`
- Data: ```
    {
      "ip": "string", //IPv6 address in canonical form
      "prefix_len": int,
      "profile_id": int
    }
    ```
- Result: 200 OK

##### Delete an IPv6 address  


- Type: DELETE
- URL: `<domain>/net6/<ipv6>`
- Result: 204 No Content, no body

### IPv4 NAT methods

<div class="pointer-container" id="bkmrk-%C2%A0-12"><div class="pointer anim is-page-editable"><svg class="svg-icon" data-icon="link" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg><div class="input-group inline block"> <button class="button outline icon" data-clipboard-target="#pointer-url" title="Copy Link" type="button"><svg class="svg-icon" data-icon="copy" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></button></div><svg class="svg-icon" data-icon="edit" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></div></div>##### Create an IPv4 NAT entry  


- Type: POST
- URL: `<domain>/napt/`
- Data: ```
    {
      "ip": "string", //IPv4 address in canonical form
      "lower_port_bound": int,
      "upper_port_bound": int,
      "profile_id": int
    }
    ```
- Result: 201 Created

##### Create multiple IPv4 NAT entries  


- Type: POST
- URL: `<domain>/napt/batch`
- Data: ```
    [
      {
      	"ip": "string", //IPv4 address in canonical form
      	"lower_port_bound": int,
      	"upper_port_bound": int,
      	"profile_id": int
      },
      
    ]
    ```
- Result: 201 Created

##### Get all IPv4 NAT entries by IP  


- Type: GET
- URL: `<domain>/napt/<int_ip>`
- Result: 200 OK

##### Get a specific IPv4 NAT entry  


- Type: GET
- URL: `<domain>/napt/<int_ip>/<lower_port_bound>/<upper_port_bound>`
- Result: 200 OK

##### Update an IPv4 NAT entry  


- Type: PATCH
- URL: `<domain>/napt/<int_ip>/<lower_port_bound>/<upper_port_bound>`
- Data: ```
    {
      "ip": "string", //IPv4 address in canonical form
      "lower_port_bound": int,
      "upper_port_bound": int,
      "profile_id": int
    }
    ```
- Result: 200 OK

##### Delete an IPv4 NAT entry  


- Type: DELETE
- URL: `<domain>/napt/<int_ip>/<lower_port_bound>/<upper_port_bound>`
- Result: 204 No Content, no body

##### Delete multiple IPv4 NAT entries  


- Type: DELETE
- URL: `<domain>/napt/batch`
- Data: ```
    [
      {
      	"ip": "string", //IPv4 address in canonical form
      	"lower_port_bound": int,
      	"upper_port_bound": int,
      	"profile_id": int
      },
      
    ]
    ```
- Result: 204 No Content, no body

### AppBlocker methods

##### Get a list of all available AppBlocker categories  


- Type: GET
- URL: `<domain>/app_aware/application/`
- Result: 200 OK