# Enhanced Cyber Threat Intelligence with CrowdSec, VictoriaMetrics & Grafana for Pangolin Setups

**URL:** <https://forum.hhf.technology/t/enhanced-cyber-threat-intelligence-with-crowdsec-victoriametrics-grafana-for-pangolin-setups/1978>\
**Category:** Guides & Tutorials\
**Tags:** crowdsec, docker, pangolin\
**Created:** [May 16, 2025, 10:57am UTC](https://forum.hhf.technology/t/enhanced-cyber-threat-intelligence-with-crowdsec-victoriametrics-grafana-for-pangolin-setups/1978 "2025-05-16T10:57:45Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![player684](https://forum.hhf.technology/user_avatar/forum.hhf.technology/player684/32/677_2.png) [@player684](https://forum.hhf.technology/u/player684)\
**Post date:** [May 16, 2025, 10:57am UTC](https://forum.hhf.technology/t/enhanced-cyber-threat-intelligence-with-crowdsec-victoriametrics-grafana-for-pangolin-setups/1978/1 "2025-05-16T10:57:45Z")

</div>

**Guide Version:** 1.0  
**Last Updated:** Friday, May 16, 2025

**Introduction:**  
This guide will walk you through integrating VictoriaMetrics with your existing CrowdSec instance (as part of a “Pangolin-like” Docker setup) and visualizing rich threat intelligence data in Grafana. We’ll leverage CrowdSec’s HTTP notifications to send detailed alert data to VictoriaMetrics, which Grafana will then use as a data source. This provides a powerful, self-hosted alternative to CrowdSec’s default metrics, offering deeper insights into the threats your services are facing, including geolocation, ASN information, and Traefik router details.

 ![image](https://forum-cdn.hhf.technology/original/2X/b/bba3efbd8858a34011d5b9f92e59335d2c7c6e2d.png)

This guide assumes you’re using a setup similar to the “Pangolin” configuration, which typically involves:

- A main `docker-compose.yml` for services like Traefik, CrowdSec, and other applications.
- A separate `docker-compose-monitoring.yml` for Prometheus, Grafana, etc.
- Both compose setups are linked via a shared external Docker network (e.g., `pangolin`).
- CrowdSec is configured to monitor Traefik logs.

**Prerequisites:**

1. A working “Pangolin-like” Docker environment with:
  - CrowdSec running and configured (especially for Traefik logs).
  - Grafana running.
  - Both CrowdSec and Grafana (and soon VictoriaMetrics) connected to the same shared Docker network (referred to as `pangolin` in this guide).
  - Your main services defined in a `docker-compose.yml` (e.g., located at `~/Pangolin/docker-compose.yml`).
  - Your monitoring services defined in `docker-compose-monitoring.yml` (e.g., at `~/Pangolin/docker-compose-monitoring.yml`).
  - A directory structure like `~/Pangolin/config/crowdsec/` for CrowdSec configurations.

2. `docker` and `docker-compose` installed on your host.
3. Basic familiarity with editing YAML files and running Docker commands.

**Overview of Changes:**

1. Add VictoriaMetrics as a new service in your `docker-compose-monitoring.yml`.
2. Create a new CrowdSec HTTP notification handler to format and send alert data.
3. Update your CrowdSec profiles to use this new notification handler.
4. Configure Grafana to use VictoriaMetrics as a data source.
5. Import a pre-built Grafana dashboard (ID `21689`) to visualize the data.

* * *

**Step-by-Step Setup Process:**

**Step 1: Prepare Directory for VictoriaMetrics Data**  
VictoriaMetrics needs a persistent volume to store its time-series data. We’ll create a directory for this within your existing configuration structure.  
On your Docker host, run:

```bash
mkdir -p ~/Pangolin/config/victoriametrics_data

```

**Step 2: Add VictoriaMetrics to Your Monitoring Docker Compose File**  
Edit your `docker-compose-monitoring.yml` file (e.g., `~/Pangolin/docker-compose-monitoring.yml`) and add the following service definition for `victoriametrics`. Place it alongside your existing `prometheus`, `grafana` services:

```yaml
networks:
  pangolin: # Ensure this matches your existing external network name
    external: true

services:
  # ... your existing prometheus, grafana, node-exporter, etc. services ...

  victoriametrics: # <-- NEW SERVICE DEFINITION STARTS HERE
    image: victoriametrics/victoria-metrics:latest
    container_name: victoriametrics
    restart: unless-stopped
    expose: # Exposes port 8428 only to other containers on the 'pangolin' network
      - "8428"
    # If you need to test VictoriaMetrics directly from your host (e.g., with curl),
    # you can temporarily change 'expose:' to 'ports: ["8428:8428"]'
    volumes:
      - ./config/victoriametrics_data:/victoria-metrics-data # Maps to ~/Pangolin/config/victoriametrics_data
    command:
      - '--storageDataPath=/victoria-metrics-data'
      - '--httpListenAddr=:8428' # Listen on all interfaces within the container on port 8428
      - '--retentionPeriod=3' # Example: Retain data for 3 months. Adjust as needed (e.g., "12m" for 12 months).
    networks:
      - pangolin # Connect to your shared network
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
  # <-- NEW SERVICE DEFINITION ENDS HERE

  # prometheus:
  # ... (rest of your prometheus config) ...
  # grafana:
  # ... (rest of your grafana config) ...

```

- **`expose: - "8428"`** : This makes VictoriaMetrics available to other containers on the `pangolin` network (like CrowdSec and Grafana) via `http://victoriametrics:8428`.
- **`volumes`** : The path `./config/victoriametrics_data` is relative to the location of your `docker-compose-monitoring.yml`.
- **`retentionPeriod`** : Adjust this based on how long you want to keep the detailed alert data.

**Step 3: Create the CrowdSec HTTP Notification Handler**  
This file tells CrowdSec how to format and where to send the alert data.  
Create a new file named `http_victoriametrics.yaml` in your CrowdSec notifications directory on the host:  
Path: `~/Pangolin/config/crowdsec/notifications/http_victoriametrics.yaml`

```yaml
type: http
name: http_victoriametrics
log_level: info # Change to 'debug' for more verbose logging during troubleshooting
format: >
  {{- range $Alert := . -}}
  {{- $traefikRouters := GetMeta . "traefik_router_name" -}}
  {{- $instanceName := env "ENROLL_INSTANCE_NAME" -}}
  {{- if not $instanceName -}}
    {{- $instanceName = "pangolin-crowdsec-default" -}}
  {{- end -}}
  {{- range .Decisions -}}
  {"metric":{" __name__":"cs_lapi_decision","instance":"{{$instanceName}}","country":"{{$Alert.Source.Cn}}","asname":"{{$Alert.Source.AsName}}","asnumber":"{{$Alert.Source.AsNumber}}","latitude":"{{$Alert.Source.Latitude}}","longitude":"{{$Alert.Source.Longitude}}","iprange":"{{$Alert.Source.Range}}","scenario":"{{.Scenario}}","type":"{{.Type}}","duration":"{{.Duration}}","scope":"{{.Scope}}","ip":"{{.Value}}","traefik_routers":{{ printf "%q" ($traefikRouters | uniq | join ",")}}},"values": [1],"timestamps":[{{now.UTC.UnixEpoch}}000]}
  {{- end }}
  {{- end -}}
url: http://victoriametrics:8428/api/v1/import
method: POST
headers:
  Content-Type: "application/json"
  #Authorization: "<SECRET-TOKEN>" # Uncomment and configure if you set up vmauth for VictoriaMetrics later

```

- **`instance`** : This uses the `ENROLL_INSTANCE_NAME` environment variable from your CrowdSec Docker Compose setup, ensuring a meaningful instance tag.
- **`traefik_routers`** : This extracts the Traefik router name if available in the alert metadata (useful if CrowdSec is parsing Traefik logs).
- **`url`** : Points to the VictoriaMetrics service on your shared Docker network.

**Step 4: Update CrowdSec Profiles**  
Now, tell CrowdSec to use this new notification handler. Edit your existing CrowdSec profiles file:  
Path: `~/Pangolin/config/crowdsec/profiles.yaml`

Add `http_victoriametrics` to the `notifications:` list within the profiles whose alerts you want to send to VictoriaMetrics. For example:

```yaml
# ... (other profiles like captcha_remediation if you have them) ...
# ---
name: default_ip_remediation # Example profile
filters:
 - Alert.Remediation == true && Alert.GetScope() == "Ip"
decisions:
 - type: ban
   duration: 4h
notifications:
 - gotify # Your existing notification
 - discord # Your existing notification
 - http_victoriametrics # <-- ADD THIS LINE
on_success: break

---
name: default_range_remediation # Example profile
filters:
 - Alert.Remediation == true && Alert.GetScope() == "Range"
decisions:
 - type: ban
   duration: 4h
notifications:
 - gotify # Your existing notification
 - discord # Your existing notification
 - http_victoriametrics # <-- ADD THIS LINE
on_success: break

# Add to other profiles as needed

```

- Review all profiles in your `profiles.yaml` and add `http_victoriametrics` where appropriate.

**Step 5: Restart Services**  
Apply the changes:

1. **Restart CrowdSec:** Navigate to the directory containing your main `docker-compose.yml` (e.g., `~/Pangolin/`) and run:

2. **Start/Update Monitoring Stack (including VictoriaMetrics):** Navigate to the directory containing `docker-compose-monitoring.yml` (e.g., `~/Pangolin/`) and run:

**Step 6: Verify CrowdSec GeoIP Parser**  
For map visualizations and country data, ensure CrowdSec’s GeoIP enrichment is active:

```bash
# Assuming your CrowdSec container is named 'crowdsec'
docker exec -it crowdsec cscli parsers install crowdsecurity/geoip-enrich
docker exec -it crowdsec cscli collections install crowdsecurity/geoip # Recommended for modern GeoIP handling
docker exec -it crowdsec cscli hub update
docker exec -it crowdsec cscli hub upgrade

```

After running these, restart CrowdSec again:

```bash
cd ~/Pangolin
docker-compose restart crowdsec

```

**Step 7: Configure Grafana**

1. **Add VictoriaMetrics as a Data Source:**

2. **Import the Grafana Dashboard:**

**Step 8: Verify and Test**

1. **Generate Test Alerts:** If you don’t have recent CrowdSec activity, generate a test decision:

```bash
docker exec -it crowdsec cscli decisions add --ip 1.2.3.4 --reason test-dashboard --duration 10m

```

2. **Check CrowdSec Logs:**

```bash
cd ~/Pangolin
docker-compose logs --tail 50 -f crowdsec

```

Look for logs from the `http_victoriametrics` plugin indicating it’s sending data (especially if `log_level` is `debug` in the notification template). There should be no template errors.
3. **Query VictoriaMetrics Directly (Optional):**  
You can quickly check if data is arriving in VictoriaMetrics from another container on the `pangolin` network (e.g., Grafana, if it has `curl`):

```bash
docker exec -it grafana curl "http://victoriametrics:8428/api/v1/query?query=cs_lapi_decision"

```

You should see a JSON response. If `result` is not empty, data is there.
4. **View the Grafana Dashboard:** Open the imported “CrowdSec Cyber Threat Insights” dashboard in Grafana. Adjust the time range (e.g., “Last 15 minutes”) to see recent events. Data should start populating the panels.

* * *

**Troubleshooting Common Issues:**

- **No data in Grafana:**
  - Verify CrowdSec is generating alerts/decisions.
  - Check CrowdSec logs for any errors from the `http_victoriametrics` plugin. The `env` template error we troubleshooted earlier is a common pitfall if the template is incorrect.
  - Ensure VictoriaMetrics is running and accessible (`docker exec -it grafana ping victoriametrics`).
  - Confirm the correct data source is selected in the Grafana dashboard panels/variables.
  - Check the Grafana time range.

- **Map not showing data:** Ensure the GeoIP steps were completed and CrowdSec restarted.
- **Template Errors in CrowdSec logs:** Double-check the syntax of your `http_victoriametrics.yaml` file against the example provided, especially the Go template section.

* * *

**Conclusion:**  
You should now have a robust Cyber Threat Intelligence dashboard powered by your Pangolin CrowdSec instance, VictoriaMetrics, and Grafana! This setup provides valuable, self-hosted insights into the security events affecting your services. Feel free to customize the Grafana dashboard further to suit your specific needs.

Happy monitoring!

* * *

---

<div class="post-metadata">

**Author:** ![Tsunade](https://forum.hhf.technology/user_avatar/forum.hhf.technology/tsunade/32/929_2.png) [@Tsunade](https://forum.hhf.technology/u/Tsunade)\
**Post date:** [May 16, 2025, 4:52pm UTC](https://forum.hhf.technology/t/enhanced-cyber-threat-intelligence-with-crowdsec-victoriametrics-grafana-for-pangolin-setups/1978/2 "2025-05-16T16:52:46Z")

</div>

Thanks you so much for make the guide, i will give it a shot!

---

<div class="post-metadata">

**Author:** ![usr\_9](https://forum.hhf.technology/letter_avatar_proxy/v4/letter/u/74df32/32.png) [@usr\_9](https://forum.hhf.technology/u/usr_9)\
**Post date:** [June 14, 2025, 11:30pm UTC](https://forum.hhf.technology/t/enhanced-cyber-threat-intelligence-with-crowdsec-victoriametrics-grafana-for-pangolin-setups/1978/3 "2025-06-14T23:30:31Z")

</div>

I finally got it working. Crowdsec error

level=errormsg=template: :3:550: executing "" at : can’t evaluate field UnixEpoch in type time.Timeplugin:=http\_victoriametrics

Had to change in notifications/http\_victoriametrics.yaml

now.UTC.UnixEpoch`with`now.UTC.Unix

---

<div class="post-metadata">

**Author:** ![usr\_9](https://forum.hhf.technology/letter_avatar_proxy/v4/letter/u/74df32/32.png) [@usr\_9](https://forum.hhf.technology/u/usr_9)\
**Post date:** [June 14, 2025, 11:30pm UTC](https://forum.hhf.technology/t/enhanced-cyber-threat-intelligence-with-crowdsec-victoriametrics-grafana-for-pangolin-setups/1978/4 "2025-06-14T23:30:57Z")

</div>

type: http  
name: http\_victoriametrics  
log\_level: info # Change to ‘debug’ for more verbose logging during troubleshooting  
format: \>  
{{- range $Alert := . -}}  
{{- $traefikRouters := GetMeta . “traefik\_router\_name” -}}  
{{- $instanceName := env “ENROLL\_INSTANCE\_NAME” -}}  
{{- if not $instanceName -}}  
{{- $instanceName = “pangolin-crowdsec-default” -}}  
{{- end -}}  
{{- range .Decisions -}}  
{“metric”:{“ **name** ”:“cs\_lapi\_decision”,“instance”:“{{$instanceName}}”,“country”:“{{$[Alert.Source.Cn](http://Alert.Source.Cn)}}”,“asname”:“{{$Alert.Source.AsName}}”,“asnumber”:“{{$Alert.Source.AsNumber}}”,“latitude”:“{{$Alert.Source.Latitude}}”,“longitude”:“{{$Alert.Source.Longitude}}”,“iprange”:“{{$Alert.Source.Range}}”,“scenario”:“{{.Scenario}}”,“type”:“{{.Type}}”,“duration”:“{{.Duration}}”,“scope”:“{{.Scope}}”,“ip”:“{{.Value}}”,“traefik\_routers”:{{ printf “%q” ($traefikRouters | uniq | join “,”)}}},“values”: [1],“timestamps”:[{{now.UTC.Unix}}000]}  
{{- end }}  
{{- end -}}  
url: [http://victoriametrics:8428/api/v1/import](http://victoriametrics:8428/api/v1/import)  
method: POST  
headers:  
Content-Type: “application/json”  
#Authorization: “” # Uncomment and configure if you set up vmauth for VictoriaMetrics later

---

<div class="post-metadata">

**Author:** ![asudave](https://forum.hhf.technology/user_avatar/forum.hhf.technology/asudave/32/1175_2.png) [@asudave](https://forum.hhf.technology/u/asudave)\
**Post date:** [June 17, 2025, 7:33am UTC](https://forum.hhf.technology/t/enhanced-cyber-threat-intelligence-with-crowdsec-victoriametrics-grafana-for-pangolin-setups/1978/5 "2025-06-17T07:33:23Z")

</div>

I have the pangolin stack with Crowdsec set up on my vps. However, I’d like to set up this monitoring on a separate host. How would I go about doing that? i assume i’d have to have my pangolin docker network accessible from another host? Still pretty new to docker networking, etc.
