CrowdSec and NGINX JSON Log

Hello everyone.

I have successfully installed Crowdsec on my VPS and my Docker host (in my home network) and set it up so far.

My VPS serves as a gateway.

Requests from the Internet ↔ VPS ↔ SSL/VPN ↔ My-Firewall ↔ Docker-Host

So Crowdsec is installed and set up on the Docker host.

Docker host IP: 172.16.20.5
VPS VPN IP: 10.10.0.1

Here is the acquis.yaml

root@docker-vm01:/etc/crowdsec# cat acquis.yaml
#Generated acquisition file - wizard.sh (service: apache2) / files :
journalctl_filter:
 - _SYSTEMD_UNIT=apache2.service
labels:
  type: apache2
---
#Generated acquisition file - wizard.sh (service: nginx) / files :
journalctl_filter:
 - _SYSTEMD_UNIT=nginx.service
labels:
  type: nginx
---
#Generated acquisition file - wizard.sh (service: ssh) / files :
journalctl_filter:
 - _SYSTEMD_UNIT=ssh.service
labels:
  type: syslog
---
source: file
filenames:
  - /var/log/my-domain.de.json.log
labels:
  type: nginx
  format: json
root@docker-vm01:/etc/crowdsec#

the config.yaml

root@docker-vm01:/etc/crowdsec# cat config.yaml
common:
  daemonize: true
  log_media: file
  log_level: info
  log_dir: /var/log/
  log_max_size: 20
  compress_logs: true
  log_max_files: 10
config_paths:
  config_dir: /etc/crowdsec/
  data_dir: /var/lib/crowdsec/data/
  simulation_path: /etc/crowdsec/simulation.yaml
  hub_dir: /etc/crowdsec/hub/
  index_path: /etc/crowdsec/hub/.index.json
  notification_dir: /etc/crowdsec/notifications/
  plugin_dir: /usr/lib/crowdsec/plugins/
crowdsec_service:
  #console_context_path: /etc/crowdsec/console/context.yaml
  acquisition_path: /etc/crowdsec/acquis.yaml
  acquisition_dir: /etc/crowdsec/acquis.d
  parser_routines: 1
cscli:
  output: human
  color: auto
db_config:
  log_level: info
  type: sqlite
  db_path: /var/lib/crowdsec/data/crowdsec.db
  #max_open_conns: 100
  #user:
  #password:
  #db_name:
  #host:
  #port:
  flush:
    max_items: 5000
    max_age: 7d
plugin_config:
  user: nobody # plugin process would be ran on behalf of this user
  group: nogroup # plugin process would be ran on behalf of this group
api:
  client:
    insecure_skip_verify: false
    credentials_path: /etc/crowdsec/local_api_credentials.yaml
  server:
    log_level: info
    listen_uri: 172.16.20.5:1080
    profiles_path: /etc/crowdsec/profiles.yaml
    console_path: /etc/crowdsec/console.yaml
    online_client: # Central API credentials (to push signals and receive bad IPs)
      credentials_path: /etc/crowdsec/online_api_credentials.yaml
    trusted_ips: # IP ranges, or IPs which can have admin API access
      - 172.16.20.5 
      - 10.10.0.1
      - ::1
#    tls:
#      cert_file: /etc/crowdsec/ssl/cert.pem
#      key_file: /etc/crowdsec/ssl/key.pem
prometheus:
  enabled: true
  level: full
  listen_addr: 127.0.0.1
  listen_port: 6060

and the local_api_credentials.yaml

root@docker-vm01:/etc/crowdsec# cat local_api_credentials.yaml
url: http://172.16.20.5:1080
login: vps01
password: Mein_Passwort
root@docker-vm01:/etc/crowdsec#

Let’s move on to the VPS:

root@SSL-VPN-debian-4gb-nbg1-2:/etc/crowdsec# cat acquis.yaml
#Generated acquisition file - wizard.sh (service: ssh) / files : /var/log/auth.log
filenames:
  - /var/log/auth.log
labels:
  type: syslog
---
#Generated acquisition file - wizard.sh (service: linux) / files : /var/log/syslog /var/log/kern.log /var/log/messages
filenames:
  - /var/log/syslog
  - /var/log/kern.log
  - /var/log/messages
labels:
  type: syslog
---
root@SSL-VPN-debian-4gb-nbg1-2:/etc/crowdsec#

The firewall bouncer is installed on the VPS.
On the VPS, Crowdsec should protect SSH and block IPs reported by the Docker host.

But for the sake of completeness, here is also the config.yaml

root@SSL-VPN-debian-4gb-nbg1-2:/etc/crowdsec# cat config.yaml
common:
  daemonize: true
  log_media: file
  log_level: info
  log_dir: /var/log/
  log_max_size: 20
  compress_logs: true
  log_max_files: 10
config_paths:
  config_dir: /etc/crowdsec/
  data_dir: /var/lib/crowdsec/data/
  simulation_path: /etc/crowdsec/simulation.yaml
  hub_dir: /etc/crowdsec/hub/
  index_path: /etc/crowdsec/hub/.index.json
  notification_dir: /etc/crowdsec/notifications/
  plugin_dir: /usr/lib/crowdsec/plugins/
crowdsec_service:
  #console_context_path: /etc/crowdsec/console/context.yaml
  acquisition_path: /etc/crowdsec/acquis.yaml
  acquisition_dir: /etc/crowdsec/acquis.d
  parser_routines: 1
cscli:
  output: human
  color: auto
db_config:
  log_level: info
  type: sqlite
  db_path: /var/lib/crowdsec/data/crowdsec.db
  #max_open_conns: 100
  #user:
  #password:
  #db_name:
  #host:
  #port:
  flush:
    max_items: 5000
    max_age: 7d
plugin_config:
  user: nobody # plugin process would be ran on behalf of this user
  group: nogroup # plugin process would be ran on behalf of this group
api:
  client:
    insecure_skip_verify: false
    credentials_path: /etc/crowdsec/local_api_credentials.yaml
  server:
    log_level: info
    listen_uri: 127.0.0.1:8080
    profiles_path: /etc/crowdsec/profiles.yaml
    console_path: /etc/crowdsec/console.yaml
    online_client: # Central API credentials (to push signals and receive bad IPs)
      credentials_path: /etc/crowdsec/online_api_credentials.yaml
    trusted_ips: # IP ranges, or IPs which can have admin API access
      - 127.0.0.1
      - ::1
#    tls:
#      cert_file: /etc/crowdsec/ssl/cert.pem
#      key_file: /etc/crowdsec/ssl/key.pem
prometheus:
  enabled: true
  level: full
  listen_addr: 127.0.0.1
  listen_port: 6060

the local_api_credentials.yaml

root@SSL-VPN-debian-4gb-nbg1-2:/etc/crowdsec# cat local_api_credentials.yaml
url: http://172.16.20.5:1080
login: vps01
password: Mein_Passwort

and now the crowdsec-firewall-bouncer.yaml

root@SSL-VPN-debian-4gb-nbg1-2:/etc/crowdsec/bouncers# cat crowdsec-firewall-bouncer.yaml
mode: iptables
update_frequency: 10s
log_mode: file
log_dir: /var/log/
log_level: info
log_compression: true
log_max_size: 100
log_max_backups: 3
log_max_age: 30
api_url: http://172.16.20.5:1080/
api_key: Mein_API_KEY
## TLS Authentication
# cert_path: /etc/crowdsec/tls/cert.pem
# key_path: /etc/crowdsec/tls/key.pem
# ca_cert_path: /etc/crowdsec/tls/ca.crt
insecure_skip_verify: false
disable_ipv6: false
deny_action: DROP
deny_log: false
supported_decisions_types:
  - ban
#to change log prefix
#deny_log_prefix: "crowdsec: "
#to change the blacklists name
blacklists_ipv4: crowdsec-blacklists
blacklists_ipv6: crowdsec6-blacklists
#type of ipset to use
ipset_type: nethash
#if present, insert rule in those chains
iptables_chains:
  - INPUT
#  - FORWARD
#  - DOCKER-USER

## nftables
nftables:
  ipv4:
    enabled: true
    set-only: false
    table: crowdsec
    chain: crowdsec-chain
    priority: -10
  ipv6:
    enabled: true
    set-only: false
    table: crowdsec6
    chain: crowdsec6-chain
    priority: -10

nftables_hooks:
  - input
  - forward

# packet filter
pf:
  # an empty string disables the anchor
  anchor_name: ""

prometheus:
  enabled: false
  listen_addr: 127.0.0.1
  listen_port: 60601

Crowdsec also works until then.
API connection is up and running.

However, there are a few things that don’t work or are a bit confusing.

Namely: On the Docker host in the crowdsec logs it says:

time="2025-04-21T13:08:24+02:00" level=info msg="capi metrics: sending"
time="2025-04-21T13:10:18+02:00" level=info msg="Sent 9 usage metrics"
time="2025-04-21T13:12:36+02:00" level=warning msg="new IP address detected for machine 'vps01': 172.16.20.5 (old: 10.10.0.1)"
time="2025-04-21T13:14:00+02:00" level=warning msg="new IP address detected for machine 'vps01': 10.10.0.1 (old: 172.16.20.5)
"```

I don't understand this correctly. The VPS has the IP 10.10.0.1 and the Docker host 172.16.20.5

Why does this message appear? What can I do about it?

Dan the second problem:

My Nginx Proxy Manager logs are all logged in JSON format and sent to Graylog with logstash.
Works great. However, crowdsec does not seem to be able to parse json.