# Beelzebub framework docs

Make your first honeypot in minutes. Learn the basics of the beelzebub honeypot framework.

***

<figure><img src="/files/i5IGEMqpm1rjTqSbwho1" alt=""><figcaption><p>beelzebub SSH and HTTP, LLM honeypots</p></figcaption></figure>


# Quickstart

Take your first steps with the Beelzebub Framework.

The Beelzebub Framework provides a simple yaml interface to configure a honeypot. This example configure a simple SSH honeypot.&#x20;

```yaml
apiVersion: "v1"
protocol: "ssh"
address: ":22"
description: "SSH simple honeypot"
commands:
  - regex: "^ls$"
    handler: "Documents Images  Desktop Downloads .m2 .kube .ssh  .docker"
  - regex: "^pwd$"
    handler: "/home/"
  - regex: "^uname -m$"
    handler: "x86_64"
   - regex: "^docker .*$"
    handler: "Error response from daemon: dial unix docker.raw.sock: connect: connection refused"
  - regex: "^uname$"
    handler: "Linux"
  - regex: "^(.+)$"
    handler: "command not found"
serverVersion: "OpenSSH"
serverName: "ubuntu"
passwordRegex: "^(root|qwerty|Smoker666|123456|jenkins|minecraft|sinus|alex|postgres|Ly123456)$"
deadlineTimeoutSeconds: 60
```

### Run Beelzebub

We provide two quick start options for run Beelzebub: using Go compiler or docker container.

### Go compiler

```bash
git clone https://github.com/mariocandela/beelzebub.git
go mod download
go build
./beelzebub
```

### Docker compose

```bash
git clone https://github.com/mariocandela/beelzebub.git
docker compose build
docker-compose up -d
```

You can find the precompiled container at the following link: <https://hub.docker.com/r/m4r10/beelzebub>

Now that you have executed Beelzebub, you will find several pre-configured honeypots within the project. They are located inside the `configurations/services` directory, try the simple SSH honeypot on port 22

```bash
ssh root@localhost
```

{% hint style="info" %}
Password: root&#x20;
{% endhint %}


# Beelzebub API v1

### Overview

The Beelzebub Honeypot Framework provides a flexible system for creating and deploying various types of honeypots that simulate vulnerable services to detect and analyze potential attacks. The framework supports multiple protocols including HTTP, SSH, and TCP, with customizable response behaviors.

### API Structure

All API configurations in the Beelzebub Honeypot Framework follow a common pattern:

* `apiVersion`: Specifies the API version (currently "v1")
* `protocol`: Defines the protocol being emulated (http, ssh, tcp, mcp)
* `address`: The network address and port to listen on (e.g., ":8080", ":22")
* `description`: A human-readable description of the honeypot service

### Protocol-Specific Configurations

#### MCP Honeypot

**Why choose an MCP Honeypot?**

An MCP honeypot is a **decoy tool** that the agent should never invoke under normal circumstances. Integrating this strategy into your agent pipeline offers three key benefits:

* **Real-time detection of guardrail bypass attempts.**

  Instantly identify when a prompt injection attack successfully convinces the agent to invoke a restricted tool.
* **Automatic collection of real attack prompts for guardrail fine-tuning.**

  Every activation logs genuine malicious prompts, enabling continuous improvement of your filtering mechanisms.

**Example MCP Honeypot Configuration**

**mcp-8000.yaml**

```yaml
apiVersion: "v1"
protocol: "mcp"
address: ":8000"
description: "MCP Honeypot"
tools:
  - name: "tool:user-account-manager"
    description: "Tool for querying and modifying user account details. Requires administrator privileges."
    params:
      - name: "user_id"
        description: "The ID of the user account to manage."
      - name: "action"
        description: "The action to perform on the user account, possible values are: get_details, reset_password, deactivate_account"
    handler: |
      {
        "tool_id": "tool:user-account-manager",
        "status": "completed",
        "output": {
          "message": "Tool 'tool:user-account-manager' executed successfully. Results are pending internal processing and will be logged.",
          "result": {
            "operation_status": "success",
            "details": "email: kirsten@gmail.com, role: admin, last-login: 02/07/2025"
          }
        }
      }
  - name: "tool:system-log"
    description: "Tool for querying system logs. Requires administrator privileges."
    params:
      - name: "filter"
        description: "The input used to filter the logs."
    handler: |
      {
        "tool_id": "tool:system-log",
        "status": "completed",
        "output": {
          "message": "Tool 'tool:system-log' executed successfully. Results are pending internal processing and will be logged.",
          "result": {
            "operation_status": "success",
            "details": "Info: email: kirsten@gmail.com, last-login: 02/07/2025"
          }
        }
      }
```

**Invoke remotely: beelzebub:port/mcp (Streamable HTTPServer).**

#### HTTP Honeypot

HTTP honeypots simulate web servers and web applications, allowing for customized responses to incoming HTTP requests.

**Sample Configuration:**

```yaml
apiVersion: "v1"
protocol: "http"
address: ":8080"
description: "Apache 401"
commands:
  - regex: ".*"
    handler: "Unauthorized"
    headers:
      - "www-Authenticate: Basic"
      - "server: Apache"
    statusCode: 401
```

**Key Components:**

* `commands`: Array of command configurations
  * `regex`: Regular expression pattern to match incoming requests
  * `handler`: Response content to return
  * `headers`: HTTP headers to include in the response
  * `statusCode`: HTTP status code to return

**Plugin Support:**

* **The HTTP protocol supports the LLMHoneypot plugin for AI-powered responses**

#### SSH Honeypot

SSH honeypots simulate SSH servers, providing interactive command-line interfaces to attackers.

**Sample Configuration (Standard):**

```yaml
apiVersion: "v1"
protocol: "ssh"
address: ":22"
description: "SSH interactive"
commands:
  - regex: "^ls$"
    handler: "Documents Images Desktop Downloads .m2 .kube .ssh .docker"
  # Additional command patterns...
  - regex: "^(.+)$"
    handler: "command not found"
serverVersion: "OpenSSH"
serverName: "ubuntu"
passwordRegex: "^(root|toor)$"
deadlineTimeoutSeconds: 60
```

**Sample Configuration (LLM-powered):**

```yaml
apiVersion: "v1"
protocol: "ssh"
address: ":2222"
description: "SSH interactive ChatGPT"
commands:
  - regex: "^(.+)$"
    plugin: "LLMHoneypot"
serverVersion: "OpenSSH"
serverName: "ubuntu"
passwordRegex: "^(root|qwerty|Smoker666|123456|jenkins|minecraft|sinus|alex|postgres|Ly123456)$"
deadlineTimeoutSeconds: 120
plugin:
  llmProvider: "openai"
  llmModel: "gpt-4o"
  openAISecretKey: "sk-proj-1234567890"
```

**Key Components:**

* `commands`: Array of command patterns and responses
  * `regex`: Regular expression to match user commands
  * `handler`: Text output to display in response to the command
  * `plugin`: Optional plugin name to handle the command (e.g., "LLMHoneypot")
* `serverVersion`: SSH server version string to display
* `serverName`: Server name to display (e.g., "ubuntu")
* `passwordRegex`: Regular expression defining accepted passwords
* `deadlineTimeoutSeconds`: Session timeout in seconds

**Plugin Configuration:**

* For LLM-powered SSH honeypots:
  * `llmProvider`: The LLM service provider (e.g., "openai", "ollama")
  * `llmModel`: The specific model to use (e.g., "gpt-4o")
  * `openAISecretKey`: API key for the LLM service

#### TCP Honeypot

TCP honeypots emulate various TCP-based services with customizable banners.

**Sample Configuration:**

```yaml
apiVersion: "v1"
protocol: "tcp"
address: ":3306"
description: "Mysql 8.0.29"
banner: "8.0.29"
deadlineTimeoutSeconds: 10
```

**Key Components:**

* `banner`: Text sent to clients upon connection
* `deadlineTimeoutSeconds`: Connection timeout in seconds

### LLMHoneypot Plugin

The LLMHoneypot plugin provides AI-powered responses to attacker inputs using language models.

**Compatibility:** Only available for HTTP, SSH and Telnet protocols.

**Configuration Parameters:**

* `llmProvider`: The AI service provider (currently supports "**openai**", "**ollama**")
* `llmModel`: The language model to use (e.g., "gpt-4o")
* `openAISecretKey`: Authentication key for the LLM service
* `prompt`: Custom prompt to customize the honeypot
* `host`: Custom URL to customize the AI service endpoint
* `inputValidationEnabled`: Whether to perform input validation for malicious prompts
* `inputValidationPrompt`: Custom prompt for the input validation model
* `outputValidationEnabled`: Whether to perform output validation for malicious responses
* `outputValidationPrompt`: Custom prompt for the output validation model
* `rateLimitEnabled`: Whether to enable IP-based rate limiting (default: `false`)
* `rateLimitRequests`: Maximum number of requests allowed per IP within the time window
* `rateLimitWindowSeconds`: Duration of the rate limiting time window in seconds

### Best Practices

1. **Port Selection:**
   * Use standard ports for better attacker engagement (e.g., :22 for SSH, :80/:443 for HTTP)
   * For multiple instances of the same protocol, use non-standard ports for additional honeypots
2. **Response Configuration:**
   * Create realistic command responses that mimic actual systems
   * Include deliberate vulnerabilities or information leaks to engage attackers
3. **LLM Integration:**
   * Use LLM-powered honeypots for more dynamic and convincing interactions
   * Use guardrails to avoid the LLM being jailbroken
4. **Password Complexity:**
   * Include common weak passwords in `passwordRegex` to attract brute force attempts
   * Mix simple passwords with moderately complex ones for realistic representation
5. **Session Management:**
   * Set appropriate `deadlineTimeoutSeconds` based on expected interaction patterns
   * Lower timeouts (10-30 seconds) for simple services
   * Higher timeouts (60-120+ seconds) for interactive sessions

### Implementation Examples

#### Basic HTTP Authentication Honeypot

```yaml
apiVersion: "v1"
protocol: "http"
address: ":80"
description: "Apache Basic Auth"
commands:
  - regex: ".*"
    handler: "Unauthorized"
    headers:
      - "www-Authenticate: Basic"
      - "server: Apache/2.4.41 (Ubuntu)"
    statusCode: 401
```

#### Interactive SSH Honeypot with LLM

```yaml
apiVersion: "v1"
protocol: "ssh"
address: ":22"
description: "SSH interactive with AI"
commands:
  - regex: "^(.+)$"
    plugin: "LLMHoneypot"
serverVersion: "OpenSSH_8.2p1"
serverName: "ubuntu"
passwordRegex: "^(root|admin|password|123456)$"
deadlineTimeoutSeconds: 120
plugin:
    llmProvider: "openai"
    llmModel: "gpt-4o"
    openAISecretKey: "sk-proj-XXXXXXXXXXXX"
```

#### Database Service Honeypot

```yaml
apiVersion: "v1"
protocol: "tcp"
address: ":3306"
description: "MySQL Server"
banner: "5.7.38-log MySQL Community Server (GPL)"
deadlineTimeoutSeconds: 15
```


# Kubernetes deployment

Kubernetes environments are particularly vulnerable to lateral movement due to their distributed nature, complex networking, and the potential for compromised pods, service accounts, or nodes to serve

Requirements:

1. kubectl installed and context configured <https://kubernetes.io/docs/tasks/tools/install-kubectl/>
2. helm installed <https://helm.sh/docs/intro/quickstart/>

**Below are the commands to download, configure and deploy Beelzebub.**

1. Clone Beelzebub repository:

```
$ git clone https://github.com/mariocandela/beelzebub.git
```

2. You can rewrite the chart [default values](https://github.com/mariocandela/beelzebub/blob/main/beelzebub-chart/values.yaml) with a `custom-values.yaml`&#x20;

Follow example of `custom-values.yaml`

```
image:
  repository: m4r10/beelzebub
  pullPolicy: IfNotPresent
  tag: v3.0.0

beelsebubServiceConfigs: |
  apiVersion: "v1"
  protocol: "ssh"
  address: ":2222"
  description: "SSH interactive"
  commands:
    - regex: "^ls$"
      handler: "Documents Images  Desktop Downloads .m2 .kube .ssh  .docker"
    - regex: "^pwd$"
      handler: "/home/"
    - regex: "^uname -m$"
      handler: "x86_64"
    - regex: "^docker ps$"
      handler: "CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES"
    - regex: "^docker .*$"
      handler: "Error response from daemon: dial unix docker.raw.sock: connect: connection refused"
    - regex: "^uname$"
      handler: "Linux"
    - regex: "^ps$"
      handler: "  PID TTY           TIME CMD\n21642 ttys000    0:00.07 /bin/dockerd"
    - regex: "^(.+)$"
      handler: "command not found"
  serverVersion: "OpenSSH"
  serverName: "ubuntu"
  passwordRegex: "^(root|qwerty|Smoker666|123456|jenkins|minecraft|sinus|alex|postgres|Ly123456)$"
  deadlineTimeoutSeconds: 60

service:
  type: ClusterIP
  port: 2222
```

Deploy:

```
$ helm install beelzebub ./beelzebub-chart
```

Deploy using custom values:

```
$ helm install beelzebub ./beelzebub-chart -f custom-values.yaml
```

<figure><img src="/files/6pxy0KRxQHyRY3NMrBDK" alt=""><figcaption></figcaption></figure>


# SSH LLM Honeypot

Follow a SSH LLM Honeypot using OpenAI as provider LLM:

Using LLM plugin AI acts as a Linux terminal and works as a high-interaction honeypot. However, it operates as a low-interaction honeypot, providing enhanced security without requiring constant supervision.

```yaml
apiVersion: "v1"
protocol: "ssh"
address: ":2222"
description: "SSH LLM Honeypot OpenAI GPT-4o"
commands:
  - regex: "^(.+)$"
    plugin: "LLMHoneypot"
serverVersion: "OpenSSH"
serverName: "ubuntu"
passwordRegex: "^(root|qwerty|Smoker666|123456|jenkins|minecraft|sinus|alex|postgres|Ly123456)$"
deadlineTimeoutSeconds: 60
plugin:
   llmProvider: "openai"
   llmModel: "gpt-4o"
   openAISecretKey: "sk-proj-123456"
```

Add your OpenAI SecretKey, and enjoy with your honeypot.

```bash
ssh root@localhost -p 2222
```


# Logs

#### Field Definitions for Beelzebub Logs

Here is the structured JSON definition of each field in Beelzebub logs:

* Command: The command entered by the attacker.
* CommandOutput: The honeypot's response.
* DateTime: The date and time of the attack.
* Description: A description of the honeypot configuration.
* ID: The unique identifier for each attack.
* Location: Details regarding the attack's origin.
* Msg: Information regarding the state callback.
* Protocol: The protocol used by the honeypot (SSH, HTTP, or TCP).
* RemoteAddr: The attacker's IP address and local post (IP:Port).
* Status: The interaction stage (Start, Stop, or Interaction). In an SSH session, the status is Interaction.


# Docker API Honeypot

This configuration was created by Akamai's hunt team, at the following link the original version:

<https://github.com/akamai/Akamai-Hunt/blob/main/HoneypotConf/docker_api_honeypot_conf.yaml>

```yaml
apiVersion: "v1"
protocol: "http"
address: ":2375"
description: "Docker Remote API honeypot (Docker/24.0.7 on linux, API 1.43, Linode host)"

commands:
  - regex: "^/_ping/?$"
    headers:
      - "Content-Type: text/plain; charset=utf-8"
      - "Server: Docker/24.0.7 (linux)"
      - "Api-Version: 1.43"
      - "Docker-Experimental: false"
      - "Ostype: linux"
    statusCode: 200
    handler: "OK"
  - regex: "^/v1\\.(\\d{2})/_ping/?$"
    headers:
      - "Content-Type: text/plain; charset=utf-8"
      - "Server: Docker/24.0.7 (linux)"
      - "Api-Version: 1.43"
      - "Docker-Experimental: false"
      - "Ostype: linux"
    statusCode: 200
    handler: "OK"

  - regex: "^/v1\\.(\\d{2})/version/?$"
    headers:
      - "Content-Type: application/json"
      - "Server: Docker/24.0.7 (linux)"
      - "Api-Version: 1.43"
      - "Docker-Experimental: false"
      - "Ostype: linux"
    statusCode: 200
    handler: |
      {
        "Platform": {"Name": "Docker Engine"},
        "Components": [
          {
            "Name": "Engine",
            "Version": "24.0.7",
            "Details": {
              "ApiVersion": "1.43",
              "MinAPIVersion": "1.12",
              "GitCommit": "b3e4c28f4dc06a09c1fa7a1ce3d2a8f1e9d741f6",
              "GoVersion": "go1.21.4",
              "Os": "linux",
              "Arch": "amd64",
              "BuildTime": "2024-11-12T10:30:00.000000000Z"
            }
          }
        ],
        "Version": "24.0.7",
        "ApiVersion": "1.43",
        "MinAPIVersion": "1.12",
        "GitCommit": "b3e4c28f4dc06a09c1fa7a1ce3d2a8f1e9d741f6",
        "GoVersion": "go1.21.4",
        "Os": "linux",
        "Arch": "amd64",
        "KernelVersion": "5.15.0-106-generic",
        "Experimental": false
      }

  - regex: "^/version/?$"
    headers:
      - "Content-Type: application/json"
      - "Server: Docker/24.0.7 (linux)"
      - "Api-Version: 1.43"
      - "Docker-Experimental: false"
      - "Ostype: linux"
    statusCode: 200
    handler: |
      {
        "Platform": {"Name": "Docker Engine"},
        "Components": [
          {
            "Name": "Engine",
            "Version": "24.0.7",
            "Details": {
              "ApiVersion": "1.43",
              "MinAPIVersion": "1.12",
              "GitCommit": "b3e4c28f4dc06a09c1fa7a1ce3d2a8f1e9d741f6",
              "GoVersion": "go1.21.4",
              "Os": "linux",
              "Arch": "amd64",
              "BuildTime": "2024-11-12T10:30:00.000000000Z"
            }
          }
        ],
        "Version": "24.0.7",
        "ApiVersion": "1.43",
        "MinAPIVersion": "1.12",
        "GitCommit": "b3e4c28f4dc06a09c1fa7a1ce3d2a8f1e9d741f6",
        "GoVersion": "go1.21.4",
        "Os": "linux",
        "Arch": "amd64",
        "KernelVersion": "5.15.0-106-generic",
        "Experimental": false
      }

  - regex: "^/info/?$"
    headers:
      - "Content-Type: application/json"
      - "Server: Docker/24.0.7 (linux)"
      - "Api-Version: 1.43"
    statusCode: 200
    handler: |
      {
        "ID": "e3b7a4a7a7a74a84b86f0e2c4b0a9b1b8d37b0e241d75b7d1f0e2cd27b3c1e55",
        "Containers": 6,
        "ContainersRunning": 6,
        "ContainersPaused": 0,
        "ContainersStopped": 0,
        "Images": 9,
        "Driver": "overlay2",
        "DriverStatus": [["Backing Filesystem","extfs"],["Supports d_type","true"],["Native Overlay Diff","true"]],
        "Plugins": {"Volume": ["local"], "Network": ["bridge","host","null"], "Log": ["json-file","local"]},
        "MemoryLimit": true,
        "SwapLimit": true,
        "KernelMemory": true,
        "CPUSet": true,
        "CPUShares": true,
        "IPv4Forwarding": true,
        "BridgeNfIptables": true,
        "BridgeNfIp6tables": true,
        "OOMKillDisable": true,
        "Warnings": null,
        "OperatingSystem": "Ubuntu 22.04.4 LTS",
        "OSVersion": "22.04",
        "OSType": "linux",
        "Architecture": "x86_64",
        "NCPU": 4,
        "MemTotal": 8178892800,
        "DockerRootDir": "/var/lib/docker",
        "HttpProxy": "",
        "HttpsProxy": "",
        "NoProxy": "",
        "Name": "li-docker-01",
        "ServerVersion": "24.0.7",
        "DefaultRuntime": "runc",
        "Runtimes": {"runc": {"path": "runc"}},
        "Swarm": {"LocalNodeState": "inactive"},
        "LiveRestoreEnabled": false
      }

  - regex: "^/images/json(?:\\?.*)?/?$"
    headers:
      - "Content-Type: application/json"
      - "Server: Docker/24.0.7 (linux)"
    statusCode: 200
    handler: |
      [
        {"Id":"sha256:0f9c7dd2b51b46a3c8b6f8a0d1e24f6f8e8dd7131f4bc779e0c5b5b2a84e83ce","RepoTags":["nginx:1.21.6"],"Size":141943872,"VirtualSize":141943872,"Created":1691577600},
        {"Id":"sha256:6ab2f8c0a2e124e5f1d6a91d5bf0cf8d3c3227e1f88e4a0e6b0f0b9f7f6f2b41","RepoTags":["redis:5.0.14"],"Size":104857600,"VirtualSize":104857600,"Created":1691664000},
        {"Id":"sha256:d1b4a12a99e5c3c2f65b2d9b49d84eb0f8a91bf2841b0a2c2b9ed5fe0c6a6a31","RepoTags":["postgres:11.12"],"Size":223346688,"VirtualSize":223346688,"Created":1691750400},
        {"Id":"sha256:3c94a0a7d7e41d9c1a03d2a46b7f54b2e3b1a6a1a7465f0abf0dd0b91a2ddee0","RepoTags":["prom/prometheus:v2.26.0"],"Size":176160768,"VirtualSize":176160768,"Created":1691836800},
        {"Id":"sha256:94c5a86f7b82b0e3e09f1ec9f8d0a7b1c5e6d237b4a9e1d9a1f0d3b2a6a7b1e9","RepoTags":["grafana/grafana:8.3.0"],"Size":278921216,"VirtualSize":278921216,"Created":1691923200},
        {"Id":"sha256:2a5ec9c0e75a4e8e9f8a17b6c5d1a7b0e93e1af2d6c6e2a9f8a3c2d4b5e6f7a8","RepoTags":["tiangolo/uvicorn-gunicorn-fastapi:python3.11"],"Size":312475648,"VirtualSize":312475648,"Created":1692009600},
        {"Id":"sha256:7a8b9c0d1e2f3a4b5c6d7e8f091a2b3c4d5e6f70a1b2c3d4e5f6a7b8c9d0e1f2","RepoTags":["alpine:3.16"],"Size":56623104,"VirtualSize":56623104,"Created":1692096000},
        {"Id":"sha256:bb51a5b13adf41a1bf67b1a2c0e5b7cd0a59ff1c99d57a1d7e64e4f5a47a2dd3","RepoTags":["busybox:1.36"],"Size":22282240,"VirtualSize":22282240,"Created":1692182400},
        {"Id":"sha256:2f8e405fd7a54d27a8f9a2e3c5d7b9e0a1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6","RepoTags":["coredns/coredns:1.11.3"],"Size":46661632,"VirtualSize":46661632,"Created":1692268800}
      ]

  - regex: "^/containers/json(?:\\?.*)?/?$"
    headers:
      - "Content-Type: application/json"
      - "Server: Docker/24.0.7 (linux)"
    statusCode: 200
    handler: |
      [
        {"Id":"a0c2c51c1f7a4b20a9cc1a0b4a9b06f3040c14b496f0f3c21bd7e0f3ae90f7b6","Names":["/web-frontend"],"Image":"nginx:1.21.6","ImageID":"sha256:0f9c7dd2b51b46a3c8b6f8a0d1e24f6f8e8dd7131f4bc779e0c5b5b2a84e83ce","Command":"nginx -g 'daemon off;'","Created":1723276934,"State":"running","Status":"Up 3 days","Ports":[{"PrivatePort":80,"Type":"tcp"}],"Labels":{"app":"web-frontend"},"HostConfig":{"NetworkMode":"bridge"},"NetworkSettings":{"Networks":{"bridge":{"IPAddress":"172.17.0.2"}}}},
        {"Id":"1df1a9b7501f4d56a4eb30b6a8e58d3ce3d0883a2df1432593a5b9eec8db4231","Names":["/api-service"],"Image":"tiangolo/uvicorn-gunicorn-fastapi:python3.11","ImageID":"sha256:2a5ec9c0e75a4e8e9f8a17b6c5d1a7b0e93e1af2d6c6e2a9f8a3c2d4b5e6f7a8","Command":"/start-reload.sh","Created":1723277131,"State":"running","Status":"Up 3 days","Ports":[{"PrivatePort":8000,"Type":"tcp"}],"Labels":{"app":"api-service"},"HostConfig":{"NetworkMode":"bridge"},"NetworkSettings":{"Networks":{"bridge":{"IPAddress":"172.17.0.3"}}}},
        {"Id":"c32e6d4f2fa54c6fb4e0a4d85f8c7f8f30bfb2b5e1c8412398e2b8a8fb2c07d1","Names":["/redis"],"Image":"redis:5.0.14","ImageID":"sha256:6ab2f8c0a2e124e5f1d6a91d5bf0cf8d3c3227e1f88e4a0e6b0f0b9f7f6f2b41","Command":"redis-server","Created":1723277160,"State":"running","Status":"Up 3 days","Ports":[{"PrivatePort":6379,"Type":"tcp"}],"Labels":{"app":"redis"},"HostConfig":{"NetworkMode":"bridge"},"NetworkSettings":{"Networks":{"bridge":{"IPAddress":"172.17.0.4"}}}},
        {"Id":"7a8e6c6c541b4e40b9a0c6f9a3c9a0024a6a1f6e24f44b63b39f2bbf31f7ea5e","Names":["/postgres"],"Image":"postgres:11.12","ImageID":"sha256:d1b4a12a99e5c3c2f65b2d9b49d84eb0f8a91bf2841b0a2c2b9ed5fe0c6a6a31","Command":"postgres","Created":1723277264,"State":"running","Status":"Up 3 days","Ports":[{"PrivatePort":5432,"Type":"tcp"}],"Labels":{"app":"postgres"},"HostConfig":{"NetworkMode":"bridge"},"NetworkSettings":{"Networks":{"bridge":{"IPAddress":"172.17.0.5"}}}},
        {"Id":"8c7b2d98c8bc4d27a74d0a9e4f4f7159d2d03b0c8e6b4a7e8c1d2a4f0c3e7b65","Names":["/prometheus"],"Image":"prom/prometheus:v2.26.0","ImageID":"sha256:3c94a0a7d7e41d9c1a03d2a46b7f54b2e3b1a6a1a7465f0abf0dd0b91a2ddee0","Command":"/bin/prometheus","Created":1723363561,"State":"running","Status":"Up 2 days","Ports":[{"PrivatePort":9090,"Type":"tcp"}],"Labels":{"app":"prometheus"},"HostConfig":{"NetworkMode":"bridge"},"NetworkSettings":{"Networks":{"bridge":{"IPAddress":"172.17.0.6"}}}},
        {"Id":"b2e9a8e2a4a841f1a1d4a2b6f8c6c1d79a6e2b7d4f1e4a6b9c2d1f5e8a3b7c2d","Names":["/grafana"],"Image":"grafana/grafana:8.3.0","ImageID":"sha256:94c5a86f7b82b0e3e09f1ec9f8d0a7b1c5e6d237b4a9e1d9a1f0d3b2a6a7b1e9","Command":"/run.sh","Created":1723364014,"State":"running","Status":"Up 2 days","Ports":[{"PrivatePort":3000,"Type":"tcp"}],"Labels":{"app":"grafana"},"HostConfig":{"NetworkMode":"bridge"},"NetworkSettings":{"Networks":{"bridge":{"IPAddress":"172.17.0.7"}}}}
      ]

  - regex: "^/images/[^/]+/json/?$"
    headers: ["Content-Type: application/json"]
    statusCode: 200
    handler: |
      {"Id":"sha256:0f9c7dd2b51b46a3c8b6f8a0d1e24f6f8e8dd7131f4bc779e0c5b5b2a84e83ce","RepoTags":["nginx:1.21.6"]}

  - regex: "^/networks/?$"
    headers: ["Content-Type: application/json"]
    statusCode: 200
    handler: |
      [
        {"Name":"bridge","Id":"f1a7b0d9a21e4ff3a9c2b4e3a51d7b4fe9e2d4a1c0b7f9034db9c5ea3c1f2a8e","Driver":"bridge","Scope":"local"},
        {"Name":"host","Id":"6d1e4b0a9f8c4c2bb0c7a9d4e1f3b2c08ca7e2b1a3f94d0ecb5a2e4c7a9b0d3f","Driver":"host","Scope":"local"},
        {"Name":"none","Id":"2ce7a9d10b3f4a6c8e9d0a1b2c3d4e5f60718293a4b5c6d7e8f9012a3b4c5d6e","Driver":"null","Scope":"local"}
      ]

  - regex: "^/volumes/?$"
    headers: ["Content-Type: application/json"]
    statusCode: 200
    handler: |
      {"Volumes":[
        {"CreatedAt":"2025-08-10T08:00:21Z","Driver":"local","Labels":null,"Mountpoint":"/var/lib/docker/volumes/pgdata/_data","Name":"pgdata","Scope":"local"},
        {"CreatedAt":"2025-08-11T09:15:09Z","Driver":"local","Labels":null,"Mountpoint":"/var/lib/docker/volumes/prom-data/_data","Name":"prom-data","Scope":"local"}
      ],"Warnings":null}

  - regex: "^/system/df/?$"
    headers: ["Content-Type: application/json"]
    statusCode: 200
    handler: |
      {"LayersSize":652738560,"Images":[{"Id":"sha256:0f9c7dd2b51b46a3c8b6f8a0d1e24f6f8e8dd7131f4bc779e0c5b5b2a84e83ce","Size":141943872},{"Id":"sha256:d1b4a12a99e5c3c2f65b2d9b49d84eb0f8a91bf2841b0a2c2b9ed5fe0c6a6a31","Size":223346688}],"Containers":[{"Id":"a0c2c51c1f7a4b20a9cc1a0b4a9b06f3040c14b496f0f3c21bd7e0f3ae90f7b6","SizeRootFs":73400320}]}

  - regex: "^/events(?:\\?.*)?/?$"
    headers: ["Content-Type: application/json"]
    statusCode: 200
    handler: |
      {"status":"start","id":"a0c2c51c1f7a4b20a9cc1a0b4a9b06f3040c14b496f0f3c21bd7e0f3ae90f7b6","from":"nginx:1.21.6","Type":"container","time":1723815011}
      {"status":"health_status: healthy","id":"1df1a9b7501f4d56a4eb30b6a8e58d3ce3d0883a2df1432593a5b9eec8db4231","from":"tiangolo/uvicorn-gunicorn-fastapi:python3.11","Type":"container","time":1723815059}

  - regex: "^/(v1\\.(4[0-9]|3[0-9]))?/images/json$"
    headers:
      - "Content-Type: application/json"
      - "Server: Docker/24.0.7 (linux)"
    statusCode: 200
    handler: |
      [
        {"Id":"sha256:0f9c7dd2b51b46a3c8b6f8a0d1e24f6f8e8dd7131f4bc779e0c5b5b2a84e83ce","RepoTags":["nginx:1.21.6"],"Size":141943872,"VirtualSize":141943872,"Created":1691577600},
        {"Id":"sha256:6ab2f8c0a2e124e5f1d6a91d5bf0cf8d3c3227e1f88e4a0e6b0f0b9f7f6f2b41","RepoTags":["redis:5.0.14"],"Size":104857600,"VirtualSize":104857600,"Created":1691664000},
        {"Id":"sha256:d1b4a12a99e5c3c2f65b2d9b49d84eb0f8a91bf2841b0a2c2b9ed5fe0c6a6a31","RepoTags":["postgres:11.12"],"Size":223346688,"VirtualSize":223346688,"Created":1691750400},
        {"Id":"sha256:3c94a0a7d7e41d9c1a03d2a46b7f54b2e3b1a6a1a7465f0abf0dd0b91a2ddee0","RepoTags":["prom/prometheus:v2.26.0"],"Size":176160768,"VirtualSize":176160768,"Created":1691836800},
        {"Id":"sha256:94c5a86f7b82b0e3e09f1ec9f8d0a7b1c5e6d237b4a9e1d9a1f0d3b2a6a7b1e9","RepoTags":["grafana/grafana:8.3.0"],"Size":278921216,"VirtualSize":278921216,"Created":1691923200},
        {"Id":"sha256:2a5ec9c0e75a4e8e9f8a17b6c5d1a7b0e93e1af2d6c6e2a9f8a3c2d4b5e6f7a8","RepoTags":["tiangolo/uvicorn-gunicorn-fastapi:python3.11"],"Size":312475648,"VirtualSize":312475648,"Created":1692009600},
        {"Id":"sha256:7a8b9c0d1e2f3a4b5c6d7e8f091a2b3c4d5e6f70a1b2c3d4e5f6a7b8c9d0e1f2","RepoTags":["alpine:3.16"],"Size":56623104,"VirtualSize":56623104,"Created":1692096000},
        {"Id":"sha256:bb51a5b13adf41a1bf67b1a2c0e5b7cd0a59ff1c99d57a1d7e64e4f5a47a2dd3","RepoTags":["busybox:1.36"],"Size":22282240,"VirtualSize":22282240,"Created":1692182400},
        {"Id":"sha256:2f8e405fd7a54d27a8f9a2e3c5d7b9e0a1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6","RepoTags":["coredns/coredns:1.11.3"],"Size":46661632,"VirtualSize":46661632,"Created":1692268800}
      ]

  - regex: "^/(v1\\.(4[0-9]|3[0-9]))?/containers/json.*$"
    headers:
      - "Content-Type: application/json"
      - "Server: Docker/24.0.7 (linux)"
    statusCode: 200
    handler: |
      [
        {"Id":"a0c2c51c1f7a4b20a9cc1a0b4a9b06f3040c14b496f0f3c21bd7e0f3ae90f7b6","Names":["/web-frontend"],"Image":"nginx:1.21.6","ImageID":"sha256:0f9c7dd2b51b46a3c8b6f8a0d1e24f6f8e8dd7131f4bc779e0c5b5b2a84e83ce","Command":"nginx -g 'daemon off;'","Created":1723276934,"State":"running","Status":"Up 3 days","Ports":[{"PrivatePort":80,"Type":"tcp"}],"Labels":{"app":"web-frontend"},"HostConfig":{"NetworkMode":"bridge"},"NetworkSettings":{"Networks":{"bridge":{"IPAddress":"172.17.0.2"}}}},
        {"Id":"1df1a9b7501f4d56a4eb30b6a8e58d3ce3d0883a2df1432593a5b9eec8db4231","Names":["/api-service"],"Image":"tiangolo/uvicorn-gunicorn-fastapi:python3.11","ImageID":"sha256:2a5ec9c0e75a4e8e9f8a17b6c5d1a7b0e93e1af2d6c6e2a9f8a3c2d4b5e6f7a8","Command":"/start-reload.sh","Created":1723277131,"State":"running","Status":"Up 3 days","Ports":[{"PrivatePort":8000,"Type":"tcp"}],"Labels":{"app":"api-service"},"HostConfig":{"NetworkMode":"bridge"},"NetworkSettings":{"Networks":{"bridge":{"IPAddress":"172.17.0.3"}}}},
        {"Id":"c32e6d4f2fa54c6fb4e0a4d85f8c7f8f30bfb2b5e1c8412398e2b8a8fb2c07d1","Names":["/redis"],"Image":"redis:5.0.14","ImageID":"sha256:6ab2f8c0a2e124e5f1d6a91d5bf0cf8d3c3227e1f88e4a0e6b0f0b9f7f6f2b41","Command":"redis-server","Created":1723277160,"State":"running","Status":"Up 3 days","Ports":[{"PrivatePort":6379,"Type":"tcp"}],"Labels":{"app":"redis"},"HostConfig":{"NetworkMode":"bridge"},"NetworkSettings":{"Networks":{"bridge":{"IPAddress":"172.17.0.4"}}}}
      ]

  - regex: "^/(v1\\.(4[0-9]|3[0-9]))?/containers/a0c2c51c1f7a4b20a9cc1a0b4a9b06f3040c14b496f0f3c21bd7e0f3ae90f7b6/json$"
    headers: ["Content-Type: application/json"]
    statusCode: 200
    handler: |
      {"Id":"a0c2c51c1f7a4b20a9cc1a0b4a9b06f3040c14b496f0f3c21bd7e0f3ae90f7b6","Name":"/web-frontend","Path":"nginx","Args":["-g","daemon off;"],"Image":"nginx:1.21.6","ImageID":"sha256:0f9c7dd2b51b46a3c8b6f8a0d1e24f6f8e8dd7131f4bc779e0c5b5b2a84e83ce","Created":"2025-08-10T08:02:14Z","State":{"Status":"running","Running":true,"StartedAt":"2025-08-10T08:02:25Z","Pid":2157},"Config":{"Hostname":"a0c2c51c1f7a","Env":["NGINX_VERSION=1.21.6"],"ExposedPorts":{"80/tcp":{}}},"HostConfig":{"NetworkMode":"bridge"},"NetworkSettings":{"Networks":{"bridge":{"IPAddress":"172.17.0.2"}}}}

  - regex: "^/(v1\\.(4[0-9]|3[0-9]))?/containers/1df1a9b7501f4d56a4eb30b6a8e58d3ce3d0883a2df1432593a5b9eec8db4231/json$"
    headers: ["Content-Type: application/json"]
    statusCode: 200
    handler: |
      {"Id":"1df1a9b7501f4d56a4eb30b6a8e58d3ce3d0883a2df1432593a5b9eec8db4231","Name":"/api-service","Image":"tiangolo/uvicorn-gunicorn-fastapi:python3.11","ImageID":"sha256:2a5ec9c0e75a4e8e9f8a17b6c5d1a7b0e93e1af2d6c6e2a9f8a3c2d4b5e6f7a8","Created":"2025-08-10T08:05:31Z","State":{"Status":"running","Running":true,"StartedAt":"2025-08-10T08:05:45Z","Pid":2298},"Path":"/start-reload.sh","Args":[],"Config":{"Env":["PORT=8000"],"ExposedPorts":{"8000/tcp":{}}},"HostConfig":{"NetworkMode":"bridge"},"NetworkSettings":{"Networks":{"bridge":{"IPAddress":"172.17.0.3"}}}}

  - regex: "^/(v1\\.(4[0-9]|3[0-9]))?/containers/c32e6d4f2fa54c6fb4e0a4d85f8c7f8f30bfb2b5e1c8412398e2b8a8fb2c07d1/json$"
    headers: ["Content-Type: application/json"]
    statusCode: 200
    handler: |
      {"Id":"c32e6d4f2fa54c6fb4e0a4d85f8c7f8f30bfb2b5e1c8412398e2b8a8fb2c07d1","Name":"/redis","Image":"redis:5.0.14","ImageID":"sha256:6ab2f8c0a2e124e5f1d6a91d5bf0cf8d3c3227e1f88e4a0e6b0f0b9f7f6f2b41","Created":"2025-08-10T08:06:00Z","State":{"Status":"running","Running":true,"StartedAt":"2025-08-10T08:06:12Z","Pid":2332},"Path":"redis-server","Args":[],"Config":{"Env":["REDIS_VERSION=5.0.14"],"ExposedPorts":{"6379/tcp":{}}},"HostConfig":{"NetworkMode":"bridge"},"NetworkSettings":{"Networks":{"bridge":{"IPAddress":"172.17.0.4"}}}}

  - regex: "^/(v1\\.(4[0-9]|3[0-9]))?/containers/7a8e6c6c541b4e40b9a0c6f9a3c9a0024a6a1f6e24f44b63b39f2bbf31f7ea5e/json$"
    headers: ["Content-Type: application/json"]
    statusCode: 200
    handler: |
      {"Id":"7a8e6c6c541b4e40b9a0c6f9a3c9a0024a6a1f6e24f44b63b39f2bbf31f7ea5e","Name":"/postgres","Image":"postgres:11.12","ImageID":"sha256:d1b4a12a99e5c3c2f65b2d9b49d84eb0f8a91bf2841b0a2c2b9ed5fe0c6a6a31","Created":"2025-08-10T08:07:44Z","State":{"Status":"running","Running":true,"StartedAt":"2025-08-10T08:07:59Z","Pid":2409},"Path":"postgres","Args":[],"Config":{"Env":["POSTGRES_VERSION=11.12"],"ExposedPorts":{"5432/tcp":{}}},"HostConfig":{"NetworkMode":"bridge"},"NetworkSettings":{"Networks":{"bridge":{"IPAddress":"172.17.0.5"}}}}

  - regex: "^/(v1\\.(4[0-9]|3[0-9]))?/containers/8c7b2d98c8bc4d27a74d0a9e4f4f7159d2d03b0c8e6b4a7e8c1d2a4f0c3e7b65/json$"
    headers: ["Content-Type: application/json"]
    statusCode: 200
    handler: |
      {"Id":"8c7b2d98c8bc4d27a74d0a9e4f4f7159d2d03b0c8e6b4a7e8c1d2a4f0c3e7b65","Name":"/prometheus","Image":"prom/prometheus:v2.26.0","ImageID":"sha256:3c94a0a7d7e41d9c1a03d2a46b7f54b2e3b1a6a1a7465f0abf0dd0b91a2ddee0","Created":"2025-08-11T09:12:41Z","State":{"Status":"running","Running":true,"StartedAt":"2025-08-11T09:12:58Z","Pid":3127},"Path":"/bin/prometheus","Args":[],"Config":{"ExposedPorts":{"9090/tcp":{}}},"HostConfig":{"NetworkMode":"bridge"},"NetworkSettings":{"Networks":{"bridge":{"IPAddress":"172.17.0.6"}}}}

  - regex: "^/(v1\\.(4[0-9]|3[0-9]))?/containers/b2e9a8e2a4a841f1a1d4a2b6f8c6c1d79a6e2b7d4f1e4a6b9c2d1f5e8a3b7c2d/json$"
    headers: ["Content-Type: application/json"]
    statusCode: 200
    handler: |
      {"Id":"b2e9a8e2a4a841f1a1d4a2b6f8c6c1d79a6e2b7d4f1e4a6b9c2d1f5e8a3b7c2d","Name":"/grafana","Image":"grafana/grafana:8.3.0","ImageID":"sha256:94c5a86f7b82b0e3e09f1ec9f8d0a7b1c5e6d237b4a9e1d9a1f0d3b2a6a7b1e9","Created":"2025-08-11T09:20:14Z","State":{"Status":"running","Running":true,"StartedAt":"2025-08-11T09:20:28Z","Pid":3196},"Path":"/run.sh","Args":[],"Config":{"ExposedPorts":{"3000/tcp":{}}},"HostConfig":{"NetworkMode":"bridge"},"NetworkSettings":{"Networks":{"bridge":{"IPAddress":"172.17.0.7"}}}}

  - regex: "^/(v1\\.(4[0-9]|3[0-9]))?/containers/a0c2c51c1f7a4b20a9cc1a0b4a9b06f3040c14b496f0f3c21bd7e0f3ae90f7b6/logs.*$"
    headers: ["Content-Type: text/plain; charset=utf-8"]
    statusCode: 200
    handler: |
      2025-08-15T08:10:07Z 172.17.0.1 - - "GET / HTTP/1.1" 200 612 "-" "curl/8.4.0"

  - regex: "^/(v1\\.(4[0-9]|3[0-9]))?/containers/1df1a9b7501f4d56a4eb30b6a8e58d3ce3d0883a2df1432593a5b9eec8db4231/logs.*$"
    headers: ["Content-Type: text/plain; charset=utf-8"]
    statusCode: 200
    handler: |
      INFO uvicorn.access: 172.17.0.1 - "GET /health HTTP/1.1" 200

  - regex: "^/(v1\\.(4[0-9]|3[0-9]))?/containers/c32e6d4f2fa54c6fb4e0a4d85f8c7f8f30bfb2b5e1c8412398e2b8a8fb2c07d1/logs.*$"
    headers: ["Content-Type: text/plain; charset=utf-8"]
    statusCode: 200
    handler: |
      * Ready to accept connections (Redis 5.0.14) on 0.0.0.0:6379

  - regex: "^/(v1\\.(4[0-9]|3[0-9]))?/containers/7a8e6c6c541b4e40b9a0c6f9a3c9a0024a6a1f6e24f44b63b39f2bbf31f7ea5e/logs.*$"
    headers: ["Content-Type: text/plain; charset=utf-8"]
    statusCode: 200
    handler: |
      database system is ready to accept connections (PostgreSQL 11.12)

  - regex: "^/(v1\\.(4[0-9]|3[0-9]))?/containers/8c7b2d98c8bc4d27a74d0a9e4f4f7159d2d03b0c8e6b4a7e8c1d2a4f0c3e7b65/logs.*$"
    headers: ["Content-Type: text/plain; charset=utf-8"]
    statusCode: 200
    handler: |
      level=info ts=2025-08-15T08:10:11Z caller=head.go:916 msg="WAL segment loaded" bytes=16777216

  - regex: "^/(v1\\.(4[0-9]|3[0-9]))?/containers/b2e9a8e2a4a841f1a1d4a2b6f8c6c1d79a6e2b7d4f1e4a6b9c2d1f5e8a3b7c2d/logs.*$"
    headers: ["Content-Type: text/plain; charset=utf-8"]
    statusCode: 200
    handler: |
      logger=server t=2025-08-15T08:10:11Z level=info msg="HTTP Server Listen" address=0.0.0.0:3000 protocol=http

  - regex: "^/(v1\\.(4[0-9]|3[0-9]))?/containers/[^/]+/top.*$"
    headers: ["Content-Type: application/json"]
    statusCode: 200
    handler: |
      {"Titles":["PID","USER","TIME","COMMAND"],"Processes":[["2157","root","00:00:12","nginx: master process nginx -g daemon off;"]]}

  - regex: "^/(v1\\.(4[0-9]|3[0-9]))?/containers/[^/]+/stats.*$"
    headers: ["Content-Type: application/json"]
    statusCode: 200
    handler: |
      {"read":"2025-08-15T08:10:11Z","pids_stats":{"current":6},"cpu_stats":{"cpu_usage":{"total_usage":123456789}},"memory_stats":{"usage":73400320,"limit":8178892800},"networks":{"eth0":{"rx_bytes":10240,"tx_bytes":20480}}}

  # ---------- Exec (create/json/start) ----------
  - regex: "^/(v1\\.(4[0-9]|3[0-9]))?/containers/[^/]+/exec$"
    headers: ["Content-Type: application/json"]
    statusCode: 201
    handler: |
      {"Id":"e8b3f7b41e0b4b1fa41e3c6d7c0f9a24d93ab2e2f41d4ce78b6c93f0a1b7404f"}

  - regex: "^/(v1\\.(4[0-9]|3[0-9]))?/exec/[^/]+/json$"
    headers: ["Content-Type: application/json"]
    statusCode: 200
    handler: |
      {"ID":"e8b3f7b41e0b4b1fa41e3c6d7c0f9a24d93ab2e2f41d4ce78b6c93f0a1b7404f","Running":false,"ExitCode":0,"OpenStdin":false,"OpenStderr":true,"OpenStdout":true}

  - regex: "^/(v1\\.(4[0-9]|3[0-9]))?/exec/[^/]+/start$"
    headers: ["Content-Type: application/json"]
    statusCode: 200
    handler: |
      {"ok":true}

  - regex: "^/(v1\\.(4[0-9]|3[0-9]))?/containers/create.*$"
    headers: ["Content-Type: application/json"]
    statusCode: 201
    handler: |
      {"Id":"6c8c4fba3f1d40d789b51f1a34d92f0cb3e19b7ef1a44d38a2a0f0f51c4a0c8d","Warnings":null}

  - regex: "^/(v1\\.(4[0-9]|3[0-9]))?/containers/[^/]+/(start|stop|restart|kill)$"
    headers: ["Content-Type: application/json"]
    statusCode: 204
    handler: ""

  - regex: "^/(v1\\.(4[0-9]|3[0-9]))?/containers/[^/]+$"
    headers: ["Content-Type: application/json"]
    statusCode: 204
    handler: ""

  - regex: "^/(v1\\.(4[0-9]|3[0-9]))?/images/[^/]+/json$"
    headers: ["Content-Type: application/json"]
    statusCode: 200
    handler: |
      {"Id":"sha256:0f9c7dd2b51b46a3c8b6f8a0d1e24f6f8e8dd7131f4bc779e0c5b5b2a84e83ce","RepoTags":["nginx:1.21.6"]}

  - regex: "^/(v1\\.(4[0-9]|3[0-9]))?/networks$"
    headers: ["Content-Type: application/json"]
    statusCode: 200
    handler: |
      [
        {"Name":"bridge","Id":"f1a7b0d9a21e4ff3a9c2b4e3a51d7b4fe9e2d4a1c0b7f9034db9c5ea3c1f2a8e","Driver":"bridge","Scope":"local"},
        {"Name":"host","Id":"6d1e4b0a9f8c4c2bb0c7a9d4e1f3b2c08ca7e2b1a3f94d0ecb5a2e4c7a9b0d3f","Driver":"host","Scope":"local"},
        {"Name":"none","Id":"2ce7a9d10b3f4a6c8e9d0a1b2c3d4e5f60718293a4b5c6d7e8f9012a3b4c5d6e","Driver":"null","Scope":"local"}
      ]

  - regex: "^/(v1\\.(4[0-9]|3[0-9]))?/volumes$"
    headers: ["Content-Type: application/json"]
    statusCode: 200
    handler: |
      {"Volumes":[
        {"CreatedAt":"2025-08-10T08:00:21Z","Driver":"local","Labels":null,"Mountpoint":"/var/lib/docker/volumes/pgdata/_data","Name":"pgdata","Scope":"local"},
        {"CreatedAt":"2025-08-11T09:15:09Z","Driver":"local","Labels":null,"Mountpoint":"/var/lib/docker/volumes/prom-data/_data","Name":"prom-data","Scope":"local"}
      ],"Warnings":null}

  - regex: "^/(v1\\.(4[0-9]|3[0-9]))?/system/df$"
    headers: ["Content-Type: application/json"]
    statusCode: 200
    handler: |
      {"LayersSize":652738560,"Images":[{"Id":"sha256:0f9c7dd2b51b46a3c8b6f8a0d1e24f6f8e8dd7131f4bc779e0c5b5b2a84e83ce","Size":141943872},{"Id":"sha256:d1b4a12a99e5c3c2f65b2d9b49d84eb0f8a91bf2841b0a2c2b9ed5fe0c6a6a31","Size":223346688}],"Containers":[{"Id":"a0c2c51c1f7a4b20a9cc1a0b4a9b06f3040c14b496f0f3c21bd7e0f3ae90f7b6","SizeRootFs":73400320}]}

  - regex: "^/(v1\\.(4[0-9]|3[0-9]))?/(containers|images)/(prune)$"
    headers: ["Content-Type: application/json"]
    statusCode: 200
    handler: |
      {"SpaceReclaimed":0}

  - regex: "^/(v1\\.(4[0-9]|3[0-9]))?/swarm/leave$"
    headers:
      - "Content-Type: application/json"
    statusCode: 200
    handler: |
      {"message":"Node left the swarm."}

  - regex: "^/v1\\..*$"
    headers: ["Content-Type: text/plain; charset=utf-8"]
    statusCode: 404
    handler: "page not found"

  - regex: "^/$"
    headers: ["Content-Type: text/plain; charset=utf-8"]
    statusCode: 404
    handler: "page not found"

  - regex: "^.*$"
    headers: ["Content-Type: text/plain; charset=utf-8"]
    statusCode: 404
    handler: "page not found"
```


# Apache basic auth

In this configuration, an example of how to replicate an Apache server protected by basic auth.

```yaml
apiVersion: "v1"
protocol: "http"
address: ":8080"
description: "Apache 401"
commands:
  - regex: ".*"
    handler: "Unauthorized"
    headers:
      - "www-Authenticate: Basic"
      - "server: Apache"
    statusCode: 401
```


# Ollama server

```yaml
apiVersion: "v1"
protocol: "http"
address: ":11434"
description: "Ollama honeypot"
commands:
  - regex: "index"
    handler: "Ollama is running"
    headers:
      - "content-type: text/plain; charset=utf-8"
    statusCode: 200
  - regex: "api/tags"
    handler: "{\"models\":[{\"name\":\"llava:7b\",\"model\":\"llava:7b\",\"modified_at\":\"2025-02-26T10:32:23.1418245+08:00\",\"size\":4733363376,\"digest\":\"8dd30f6b0cb19f555f2c7a7ebda861449ea2cc76bf1f44e262931f45fc81d081\",\"details\":{\"parent_model\":\"\",\"format\":\"gguf\",\"family\":\"llama\",\"families\":[\"llama\",\"clip\"],\"parameter_size\":\"7B\",\"quantization_level\":\"Q4_0\"}}]}"
    headers:
      - "content-type: application/json; charset=utf-8"
    statusCode: 200
  - regex: ".*"
    handler: "404 page not found"
    headers:
      - "content-type: text/plain; charset=utf-8"
    statusCode: 404
```


# N8N honeypot

N8N beelzebub honeypot configuration

```yaml
apiVersion: "v1"
protocol: "http"
address: ":5678"
description: "n8n - Honeypot"
 
commands:
  # ==========================================================================
  # ENDPOINT: GET /signin
  # ==========================================================================
  - regex: "^/signin$"
    handler: |
      <!DOCTYPE html>
      <html lang="en">
      <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>n8n - Sign In</title>
        <style>
          body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; 
                 background: #f5f5f5; display: flex; justify-content: center; align-items: center; 
                 height: 100vh; margin: 0; }
          .container { background: white; padding: 40px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); width: 360px; }
          .logo { text-align: center; margin-bottom: 30px; }
          .logo svg { width: 48px; height: 48px; }
          h1 { font-size: 24px; text-align: center; margin: 0 0 30px; color: #333; }
          input { width: 100%; padding: 12px; margin-bottom: 16px; border: 1px solid #ddd; 
                  border-radius: 4px; box-sizing: border-box; font-size: 14px; }
          button { width: 100%; padding: 12px; background: #ff6d5a; color: white; border: none; 
                   border-radius: 4px; cursor: pointer; font-size: 16px; font-weight: 600; }
          button:hover { background: #ff5a45; }
          .version { text-align: center; color: #999; font-size: 12px; margin-top: 20px; }
        </style>
      </head>
      <body>
        <div class="container">
          <div class="logo">
            <svg viewBox="0 0 100 100" fill="#ff6d5a"><circle cx="50" cy="50" r="45"/></svg>
          </div>
          <h1>Sign in to n8n</h1>
          <form action="/rest/login" method="post">
            <input type="email" name="email" placeholder="Email address" required>
            <input type="password" name="password" placeholder="Password" required>
            <button type="submit">Sign In</button>
          </form>
          <div class="version">n8n v1.120.0</div>
        </div>
      </body>
      </html>
    headers:
      - "Content-Type: text/html; charset=utf-8"
      - "Server: n8n"
      - "X-Powered-By: Express"
      - "X-n8n-Version: 1.120.0"
      - "Cache-Control: no-cache, no-store, must-revalidate"
    statusCode: 200
 
  # ==========================================================================
  # ENDPOINT: GET /rest/settings 
  # ==========================================================================
  - regex: "^/rest/settings$"
    handler: |
      {
        "data": {
          "n8nVersion": "1.120.0",
          "versionCli": "1.120.0",
          "databaseType": "sqlite",
          "authenticationMethod": "email",
          "defaultLocale": "en",
          "endpointWebhook": "webhook",
          "endpointWebhookTest": "webhook-test",
          "instanceId": "f8e7d6c5-b4a3-9281-7654-321fedcba098",
          "isDocker": true,
          "timezone": "Europe/Rome",
          "urlBaseWebhook": "https://n8n.example.com/",
          "urlBaseEditor": "https://n8n.example.com/",
          "executionMode": "regular",
          "pushBackend": "websocket",
          "communityNodesEnabled": true,
          "expressionEvaluator": "tmpl",
          "deployment": {
            "type": "default"
          },
          "enterprise": {
            "sharing": false,
            "ldap": false,
            "saml": false,
            "logStreaming": false,
            "advancedExecutionFilters": false,
            "variables": true,
            "sourceControl": false,
            "auditLogs": false,
            "externalSecrets": false,
            "workflowHistory": false
          },
          "security": {
            "blockFileAccessToN8nFiles": true,
            "restrictFileAccessTo": ""
          }
        }
      }
    headers:
      - "Content-Type: application/json; charset=utf-8"
      - "Server: n8n"
      - "X-Powered-By: Express"
      - "X-n8n-Version: 1.120.0"
      - "Cache-Control: no-cache"
    statusCode: 200
 
  # ==========================================================================
  # ENDPOINT: POST /rest/workflows
  # ==========================================================================
  - regex: "^/rest/workflows$"
    handler: |
      {
        "data": {
          "id": "wf_a1b2c3d4e5f67890",
          "name": "New Workflow",
          "active": false,
          "createdAt": "2025-12-25T12:00:00.000Z",
          "updatedAt": "2025-12-25T12:00:00.000Z",
          "versionId": "v1-a1b2c3d4",
          "nodes": [],
          "connections": {},
          "settings": {
            "saveExecutionProgress": true,
            "saveManualExecutions": true,
            "saveDataErrorExecution": "all",
            "saveDataSuccessExecution": "all",
            "executionTimeout": 3600,
            "timezone": "Europe/Rome"
          },
          "staticData": null,
          "tags": [],
          "sharedWith": []
        }
      }
    headers:
      - "Content-Type: application/json; charset=utf-8"
      - "Server: n8n"
      - "X-Powered-By: Express"
      - "X-n8n-Version: 1.120.0"
      - "X-Request-Id: req_f8e7d6c5b4a39281"
    statusCode: 201
 
  # ==========================================================================
  # ENDPOINT: PUT /rest/workflows/:id 
  # ==========================================================================
  - regex: "^/rest/workflows/[a-zA-Z0-9_-]+$"
    handler: |
      {
        "data": {
          "id": "wf_a1b2c3d4e5f67890",
          "name": "Updated Workflow",
          "active": false,
          "createdAt": "2025-12-20T10:30:00.000Z",
          "updatedAt": "2025-12-25T14:35:22.000Z",
          "versionId": "v2-b2c3d4e5",
          "nodes": [
            {
              "id": "start-node",
              "name": "Start",
              "type": "n8n-nodes-base.manualTrigger",
              "typeVersion": 1,
              "position": [100, 100],
              "parameters": {}
            }
          ],
          "connections": {},
          "settings": {
            "saveExecutionProgress": true,
            "saveManualExecutions": true
          }
        }
      }
    headers:
      - "Content-Type: application/json; charset=utf-8"
      - "Server: n8n"
      - "X-Powered-By: Express"
      - "X-n8n-Version: 1.120.0"
    statusCode: 200
 
  # ==========================================================================
  # ENDPOINT: POST /rest/workflows/:id/execute 
  # ==========================================================================
  - regex: "^/rest/workflows/[a-zA-Z0-9_-]+/execute$"
    handler: |
      {
        "data": {
          "executionId": "exec_9876543210fedcba",
          "mode": "manual",
          "startedAt": "2025-12-25T14:40:00.000Z",
          "status": "running",
          "workflowId": "wf_a1b2c3d4e5f67890",
          "workflowName": "Workflow",
          "data": {
            "resultData": {
              "runData": {},
              "lastNodeExecuted": "Start"
            }
          }
        }
      }
    headers:
      - "Content-Type: application/json; charset=utf-8"
      - "Server: n8n"
      - "X-Powered-By: Express"
      - "X-n8n-Version: 1.120.0"
      - "X-Execution-Id: exec_9876543210fedcba"
    statusCode: 200
 
  # ==========================================================================
  # ENDPOINT: GET /api/v1/workflows
  # ==========================================================================
  - regex: "^/api/v1/workflows$"
    handler: |
      {
        "data": [
          {
            "id": "wf_a1b2c3d4e5f67890",
            "name": "Production Workflow",
            "active": true,
            "createdAt": "2025-12-01T08:00:00.000Z",
            "updatedAt": "2025-12-24T16:30:00.000Z",
            "tags": [
              {
                "id": "tag_prod123",
                "name": "production"
              }
            ]
          },
          {
            "id": "wf_fedcba0987654321",
            "name": "Data Processing",
            "active": false,
            "createdAt": "2025-11-15T10:00:00.000Z",
            "updatedAt": "2025-12-20T12:00:00.000Z",
            "tags": []
          }
        ],
        "nextCursor": null
      }
    headers:
      - "Content-Type: application/json; charset=utf-8"
      - "Server: n8n"
      - "X-Powered-By: Express"
      - "X-n8n-Version: 1.120.0"
    statusCode: 200
 
  # ==========================================================================
  # ENDPOINT: /webhook/*
  # ==========================================================================
  - regex: "^/webhook/.*$"
    handler: |
      {
        "message": "Workflow was started",
        "executionId": "exec_webhook_1234567890",
        "success": true
      }
    headers:
      - "Content-Type: application/json; charset=utf-8"
      - "Server: n8n"
      - "X-Powered-By: Express"
      - "X-n8n-Version: 1.120.0"
      - "X-Webhook-Execution: exec_webhook_1234567890"
    statusCode: 200
 
  # ==========================================================================
  # ENDPOINT: /webhook-test/*
  # ==========================================================================
  - regex: "^/webhook-test/.*$"
    handler: |
      {
        "message": "Test webhook received",
        "mode": "test",
        "success": true
      }
    headers:
      - "Content-Type: application/json; charset=utf-8"
      - "Server: n8n"
      - "X-Powered-By: Express"
      - "X-n8n-Version: 1.120.0"
    statusCode: 200
 
  # ==========================================================================
  # ENDPOINT: POST /rest/login
  # ==========================================================================
  - regex: "^/rest/login$"
    handler: |
      {
        "data": {
          "user": {
            "id": "user_admin123",
            "email": "admin@n8n.local",
            "firstName": "Admin",
            "lastName": "User",
            "personalizationAnswers": null,
            "globalRole": {
              "id": "1",
              "name": "owner",
              "scope": "global"
            },
            "createdAt": "2025-01-01T00:00:00.000Z",
            "updatedAt": "2025-12-25T00:00:00.000Z",
            "settings": {
              "userActivated": true,
              "allowSSOManualLogin": true
            }
          }
        }
      }
    headers:
      - "Content-Type: application/json; charset=utf-8"
      - "Server: n8n"
      - "X-Powered-By: Express"
      - "X-n8n-Version: 1.120.0"
      - "Set-Cookie: n8n-auth=eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiJ1c2VyX2FkbWluMTIzIn0.fake_token; Path=/; HttpOnly; SameSite=Lax"
    statusCode: 200
 
  # ==========================================================================
  # ENDPOINT: GET /api/v1/credentials
  # ==========================================================================
  - regex: "^/api/v1/credentials$"
    handler: |
      {
        "data": [
          {
            "id": "cred_aws123",
            "name": "AWS Production",
            "type": "aws",
            "createdAt": "2025-06-01T10:00:00.000Z",
            "updatedAt": "2025-12-01T14:30:00.000Z"
          },
          {
            "id": "cred_db456",
            "name": "Database Connection",
            "type": "postgres",
            "createdAt": "2025-03-15T08:00:00.000Z",
            "updatedAt": "2025-11-20T16:00:00.000Z"
          },
          {
            "id": "cred_api789",
            "name": "Internal API Key",
            "type": "httpBasicAuth",
            "createdAt": "2025-09-10T12:00:00.000Z",
            "updatedAt": "2025-12-20T10:00:00.000Z"
          }
        ],
        "nextCursor": null
      }
    headers:
      - "Content-Type: application/json; charset=utf-8"
      - "Server: n8n"
      - "X-Powered-By: Express"
      - "X-n8n-Version: 1.120.0"
    statusCode: 200
 
  # ==========================================================================
  # ENDPOINT: GET /api/v1/executions
  # ==========================================================================
  - regex: "^/api/v1/executions.*$"
    handler: |
      {
        "data": [
          {
            "id": "exec_12345",
            "finished": true,
            "mode": "trigger",
            "retryOf": null,
            "startedAt": "2025-12-25T08:00:00.000Z",
            "stoppedAt": "2025-12-25T08:00:02.500Z",
            "workflowId": "wf_a1b2c3d4e5f67890",
            "status": "success"
          },
          {
            "id": "exec_12344",
            "finished": true,
            "mode": "manual",
            "retryOf": null,
            "startedAt": "2025-12-24T14:30:00.000Z",
            "stoppedAt": "2025-12-24T14:30:05.200Z",
            "workflowId": "wf_fedcba0987654321",
            "status": "error"
          }
        ],
        "nextCursor": null
      }
    headers:
      - "Content-Type: application/json; charset=utf-8"
      - "Server: n8n"
      - "X-Powered-By: Express"
      - "X-n8n-Version: 1.120.0"
    statusCode: 200
 
  - regex: "^/$"
    handler: |
      <!DOCTYPE html>
      <html><head><meta http-equiv="refresh" content="0;url=/signin"></head></html>
    headers:
      - "Content-Type: text/html; charset=utf-8"
      - "Server: n8n"
      - "X-Powered-By: Express"
      - "X-n8n-Version: 1.120.0"
    statusCode: 302
 
  - regex: "^/healthz?$"
    handler: |
      {
        "status": "ok"
      }
    headers:
      - "Content-Type: application/json; charset=utf-8"
      - "Server: n8n"
      - "X-Powered-By: Express"
    statusCode: 200
 
  - regex: "^.*$"
    handler: |
      {
        "code": 401,
        "message": "Unauthorized",
        "hint": "Missing or invalid API key. Set header 'X-N8N-API-KEY' or cookie 'n8n-auth'."
      }
    headers:
      - "Content-Type: application/json; charset=utf-8"
      - "Server: n8n"
      - "X-Powered-By: Express"
      - "X-n8n-Version: 1.120.0"
      - "WWW-Authenticate: Bearer realm=\"n8n\""
    statusCode: 401
```


