Learn how to maximize protection and reduce security & operational costs.

Download guide

Join us for CrowdSec Community Office Hours: June Session!

Register now

Securing Automated Application Deployment with CrowdSec and Coolify

Coolify has gained a lot of traction in this year as being an open source, self hosted alternative to Heroku, Netlify, and Vercel. It empowers users to take full control of hosting applications, databases, and services without the limitations of free tiers or other restrictions often imposed by these platforms.

There are numerous features and benefits to using Coolify, and while I can’t cover them all in this article, here’s a quick summary:

  • No hidden costs: When you use your own hardware or infrastructure, pricing remains entirely under your control. There are no surprise charges or restrictions if your applications gain popularity.
  • Complete data privacy: You are running everything on your own infrastructure, so there is no intermediary between your services and your users, which ensures full data privacy.
  • Unlimited usage: You can deploy as many applications or services as you like without worrying about limits. If you want to automate your development workflows, Coolify makes it incredibly easy.

For a complete list of benefits, take a look at the official Coolify documentation.

How does Coolify work?

While writing this article, I wanted to gain a clear understanding of how Coolify operates. 

Unlike other self-hosted dashboards, such as Portainer, which often require several steps to connect multiple servers, Coolify makes this process much more straightforward.

Coolify and SSH

Coolify operates by using SSH to connect to your servers, taking advantage of SSH’s built-in security features. This approach removes the need to expose services such as the Docker API, which are commonly targeted by cybercriminals due to frequent misconfigurations. For example, in his article published on The Hacker News, Ravie Lakshmanan highlighted how attackers exploit exposed Docker API servers to deploy crypto-mining malware.

Coolify connects to servers over SSH and supports both password and public key authentication, depending on how your SSH daemon is configured. By default, Coolify uses the root user account. While it is possible to configure Coolify to use a non-root user, this setup requires additional manual configuration. The current documentation provides guidance on how to do this, but notes that the feature is still experimental and may not guarantee full isolation.

Coolify supports a variety of deployment options depending on the type of application you want to host. Behind the scenes, Coolify uses Docker to isolate applications and relies on an upstream proxy to route traffic to the correct container. By default, Coolify uses Traefik Proxy as its proxy, which comes with built-in container discovery. This lets you define container labels that tell Traefik Proxy which hostname should route to each container.

Later, Coolify added support for Caddy as an alternative proxy, using the caddy-docker-proxy module. This community-driven tool gives Caddy the same container discovery capabilities as Traefik Proxy, making it a great addition to the platform.

Coolify and CrowdSec

While Coolify is excellent for automating and deploying your applications, it is equally important to prioritize security. This is where the CrowdSec Security Engine proves valuable, offering flexible deployment options. 

You can run the Security Engine inside a container or install it directly on the host to provide strong protection.

Installing the Security Engine on server

Depending on your host system, you can follow our Getting Started Guide, which explains how to install the Security Engine on a typical Linux server. However, I’ll walk you through a tailored guide for Coolify here.

Adding the CrowdSec package repository

We host our packages on Packagecloud, which simplifies updates and ensures you are always running the latest version. To install, run the following command:

curl -s https://install.crowdsec.net | sudo sh

Installing the CrowdSec Security Engine

The previous command only installs the CrowdSec repository, so you will still need to use your package manager to install the CrowdSec package. Since we are using Debian 12 as our distribution, you can install it with the following apt command:

sudo apt install crowdsec -y

Once CrowdSec is installed, you need to change its default API port because Traefik Proxy uses port 8080 for its dashboard. To avoid a conflict, update two configuration files located in the /etc/crowdsec/ directory.

First, open config.yaml using your preferred terminal text editor. Locate the following section and change the port to one that is not currently in use on your system. In this example, I will use port 9090:

api:
  server:
	listen_uri: 127.0.0.1:9090 ## Change port here

Next, open local_api_credentials.yaml and update the URL to match the new port:

url: http://127.0.0.1:9090 ## Change port here to match above

After making these changes, restart the CrowdSec Security Engine by running:

sudo systemctl restart crowdsec

You can then verify that everything is working correctly by checking the log file at /var/log/crowdsec.log.

Great! The Security Engine is now installed and, by default, it will begin monitoring services running on the host. However, since Coolify operates inside containers, those services will not be detected automatically, you will need to configure them manually. That said, your SSH server is already protected out of the box.

I recommend that you take a look at our post installation section in the docs, which outlines the steps you should follow after installing the Security Engine. In particular, I suggest reviewing the whitelist section to ensure that CrowdSec does not take action against trusted IP addresses.

Installing a Remediation Component

Since the CrowdSec Security Stack was designed as a modular system, it is split into two main components: the CrowdSec Security Engine, which acts as the Intrusion Detection System (IDS), and the Remediation Component, which functions as the Intrusion Prevention System (IPS) by enforcing the decisions made by CrowdSec.

The appropriate Remediation Component to install depends on your system and setup. In this guide, I will start by installing the Firewall Remediation to protect the SSH server. Later on, I will walk you through how to configure the Traefik Remediation if you are using an upstream proxy like Cloudflare and have configured Coolify to use Traefik Proxy. If you are using Caddy instead, no worries — you can still parse Caddy logs to generate local decisions.

Before installing, we need to check if your system is using the nftables backend through iptables. You can do this by running:

iptables --version

If the output includes (nf_tables), your system is using the nftables backend. On Debian 12, iptables is actually implemented as a compatibility layer over nftables. Since Docker does not fully support nftables, we will install the iptables version of the Firewall Remediation instead:

sudo apt install crowdsec-firewall-bouncer-iptables

Once installed, we need to update the configuration to apply CrowdSec rules to the DOCKER-USER chain. Docker uses this chain to evaluate packets before they are passed to any container, making it ideal for enforcing firewall decisions.

Start by editing the Firewall Remediation configuration located at:

/etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml

In the iptables_chains section, locate the line for DOCKER-USER. It is commented out by default. Remove the # in front of it and make sure it aligns with the formatting of the existing INPUT line.

While you’re there, note that the default Docker setup provided by Coolify does not enable IPv6 unless you have made custom modifications. To avoid startup issues and ensure proper chain detection, set disable_ipv6 to true.
Once these changes are made, restart the firewall bouncer service so it can pick up the updated configuration and attach to the DOCKER-USER chain correctly.

systemctl restart crowdsec-firewall-bouncer

This means that both your SSH server and any Docker-exposed ports are now preemptively protected by the Community Blocklist. Later, they will also be protected by local decisions generated from your Coolify proxy logs.

CrowdSec Acquisition

Before we configure the Coolify proxy to log access logs to stdout, we can configure CrowdSec to detect the Coolify proxy via Docker Acquisition feature, specifically a capability introduced in version 1.6.2 that allows CrowdSec to discover containers based on labels.

First, create a file named docker.yaml in the /etc/crowdsec/acquis.d/ directory with the following content:

source: docker
use_container_labels: true

This tells CrowdSec to automatically discover Docker containers that have the `crowdsec.enable=true` label and begin processing their logs accordingly to the defined `crowdsec.labels.type`.

Once the file is created and saved, you need to install the collections that you want for the Coolify proxy:

cscli collections install crowdsecurity/traefik crowdsecurity/caddy

You can safely install both Traefik Proxy and Caddy collections as this allows you to safely switch between proxies in the future without the need to remember to install either collection.

Next, restart the CrowdSec service:

sudo systemctl restart crowdsec

Once CrowdSec has been restarted, the next step is to configure the Coolify proxy container to be detectable by CrowdSec’s discovery service.

Configuring the Coolify proxy

Depending on which proxy you are using provided by Coolify, you will have to alter the configuration steps here based on the provided proxies.

⚠️ Warning: CrowdSec uses the IP address logged by the proxy. If you are using an upstream proxy such as Cloudflare, you will need to configure your web server to trust the IP addresses or ranges from which requests come. If you do this incorrectly, CrowdSec could ban Cloudflare’s IPs, which would affect all users accessing your services through the proxy.

While this guide does not cover the steps required to configure trusted IPs for your specific proxy, you can find many tutorials and examples online by searching for how to set up trusted proxies with your chosen web server and provider.

Enabling Traefik Proxy logs

By default, Traefik Proxy does not log access logs. To enable them, you can modify the command section in your server proxy configuration:

command:
  - '--accesslog=true'
  - '--ping=true' ## this should already be here

Adding --accesslog=true enables the default Common Log Format (CLF) access logs to be written to Traefik’s stdout. This is ideal, as we mentioned before we can use CrowdSec’s Docker Acquisition to read container stdout directly, without needing to mount log files from the container to the host.

If you prefer JSON-formatted logs, you can add the following line as well:

- '--accesslog.format=json'

CrowdSec supports both CLF and JSON formats from Traefik Proxy.

While editing the configuration, you can also preemptively add labels to help the CrowdSec Security Engine automatically detect and parse Traefik Proxy logs. Add the following under the labels section:

labels:
  - coolify.proxy=true ## Should already be here
  - crowdsec.enable=true
  - crowdsec.labels.type=traefik

As you can see, it is very simple to configure your containers so that CrowdSec will pick them up. It uses the Docker API to discover new containers and reads the labels to determine how to process the logs.

Caddy configuration files

Unfortunately, at the time of writing, Coolify’s method for handling Caddy configuration files does not support defining a logger globally. As a result, you will need to define a logger individually for each container you create via labels. You can track this issue to stay updated in case this configuration handling improves in the future.

For now, when you create a service that includes a host handler, you can simply add the following Caddy labels to the compose:

labels:
   - 'caddy_0.log.output=stdout'

These labels will print the default JSON logs to the stdout of the Coolify proxy. 

Note: Please make sure to only add these labels to containers that are intended to accept connections from Caddy. Applying them to unrelated containers may result in configuration errors within Caddy.

However, you also need to add the CrowdSec labels to the Caddy configuration within the server proxy configuration page. You will need to add the following labels to the Caddy container:

labels:
  - coolify.proxy=true ## Should already be here
  - crowdsec.enable=true
  - crowdsec.labels.type=caddy

These labels tell CrowdSec to monitor the stdout of the Caddy container and parse the logs using the Caddy format. 

Note: Only JSON logs from Caddy are supported at this time; other formats are not currently supported.

Checking if the proxy is detected

Once the proxy is configured as shown above, save the configuration and restart the proxy using the Coolify UI.

If you encounter an error indicating that a port is already in use, please revisit the CrowdSec installation section where we covered how to modify the default API port.

You can check the CrowdSec log file located at /var/log/crowdsec.log to see if it found the Coolify proxy container.

time="2025-04-17T16:23:09Z" level=info msg="start tail for container /coolify-proxy" container_name=/coolify-proxy type=docker

Note that the type shown in the logs refers to the acquisition type, not the type defined in the container labels.

To verify that everything is being parsed correctly, you can run the following command:

cscli metrics show acquisition

Here is an example output you should see:

You may notice that some lines are marked as parsed while others are unparsed. This is expected behavior, especially with software like Caddy, which logs various messages to stdout beyond just access logs. As long as you see the parsed counter increasing, it means everything is working correctly and CrowdSec is successfully analyzing your access logs.

Monitoring other containers

Although it is best to monitor the Coolify proxy logs since this is the main entry point handling incoming connections, you may also want to monitor the logs of applications running behind the proxy. This is especially useful because some applications do not follow industry standards when it comes to response codes.

For example, when a user attempts to log in with incorrect credentials, the application should ideally return a 401 Unauthorized status code to indicate the failure. However, some applications instead return a 200 OK, or even a 301 Redirect. A case in point is the Coolify UI itself, which returns a 301 in such scenarios. This behavior is due to how the Laravel framework handles these types of requests.

Monitoring the application logs directly allows CrowdSec to detect anomalies that might be missed if only the proxy logs are being analyzed.

Example configuration

So, using what I showed you above, you can add labels to our deployed applications that also utilise the container discovery:

services:
  wordpress:
	image: 'wordpress:latest'
	volumes:
  	- 'wordpress-files:/var/www/html'
	environment:
  	- SERVICE_FQDN_WORDPRESS
	labels:
  	- 'crowdsec.enable=true'
	- 'crowdsec.labels.type=wordpress'

With these two labels, the Security Engine will be able to find this WordPress container, start monitoring it, and attempt to parse the logs to stdout as WordPress logs. However, it is important to note that CrowdSec can only use parsers which has been installed by the user, so before you deploy this application, you would also need to run:

sudo cscli collections install crowdsecurity/wordpress

And then restart CrowdSec: sudo systemctl restart crowdsec.

Installing the Traefik Remediation Component

Earlier, when discussing which Remediation Components to use, we installed the Firewall Remediation, which blocks IP addresses at the firewall level. However, there are scenarios where this method is not effective. For example, when using Cloudflare as a proxy, the firewall only sees Cloudflare IP addresses at layer 3/4. In such cases, you need to handle remediation at layer 7.

Introducing the Traefik Remediation Component, authored by Maxlerebourg and MathieuHA from Primadviz. They participated in a Traefik hackathon and reimagined what a plugin for Traefik could accomplish.

Configuring CrowdSec

In the first part of this blog post, we covered how to configure CrowdSec to run on a different port. However, in order for Traefik Proxy to communicate with the CrowdSec Security Engine running on the host machine, we need to modify the network interface bindings.

This can be done by editing the same configuration file, config.yaml, located in /etc/crowdsec, and updating the listen_url to 0.0.0.0:9090:

api:
  server:
	listen_uri: 0.0.0.0:9090

Unlike the earlier steps, you do not need to modify the local_api_credentials.yaml file. Binding to all interfaces allows requests to 127.0.0.1:9090 to be processed correctly. You only need to update this file if you decide to change the port at this point.

After making the changes, restart the CrowdSec service:

systemctl restart crowdsec

Configuring Traefik Proxy

Before starting the configuration steps, you need to generate an API key from CrowdSec. This key will be used by Traefik Proxy for the Remediation Middleware:

cscli bouncers add coolify-proxy

Make sure to keep this key secure, as it will be required in the following steps.

The Traefik Proxy configuration is divided into two parts. First, we need to create a dynamic configuration file that contains the settings for the remediation component. On the host system, Coolify creates a directory at /data/coolify/proxy/dynamic. Inside this directory, create a file named crowdsec.yml, which will contain the following configuration:

http:
  middlewares:
    globalcrowdsec:
      plugin:
        crowdsec:
          enabled: true
          crowdsecLapiKey: CHANGEME
          crowdsecLapiScheme: http
          crowdsecLapiHost: 'host.docker.internal:9090'
          crowdsecMode: stream
          #logLevel: DEBUG

Where you see CHANGEME, replace it with the API key generated in the previous step.

If the key is lost, you can remove it and create a new one using the following commands:

cscli bouncers delete coolify-proxy
cscli bouncers add coolify-proxy

Once everything is configured correctly, save and close the file.

The next step is to configure the proxy to download additional plugins. To do this, go to Servers → Proxy and update the Compose Command section by adding the following lines:

  command:
- '--experimental.plugins.crowdsec.modulename=github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin'
- '--experimental.plugins.crowdsec.version=v1.4.2'
- '--entryPoints.http.http.middlewares=globalcrowdsec@file'
- '--entryPoints.https.http.middlewares=globalcrowdsec@file'

Note that this is not a complete list of commands. Simply append these lines to the bottom of your existing configuration.

Let us break down what this configuration does.

First, you define a plugin to be loaded by Traefik Proxy under the name crowdsec. The format follows experimental.plugins.<name>.modulename. You also need to specify the version to use, which in this case is v1.4.2. You should check the GitHub Releases page to ensure you are using the latest version.

Once the plugin is loaded, you need to configure Traefik Proxy to apply the CrowdSec Middleware to both the http and https entry points, which are the defaults within Coolify. This ensures all incoming traffic is filtered through the middleware.

The format used is globalcrowdsec@file, which refers to the name of the middleware defined in the crowdsec.yml configuration file.

Once this is configured, you can save and restart the proxy. Note that the middleware logs nothing by default, so the easiest way to see if the middleware is active is to check cscli bouncers list to see if the API key is used and has a timestamp:

cscli bouncers list

Here is an example output of the command:

Also, if you have access to the Traefik dashboard and you click on a resource, you should see the middleware defined:

Wrapping up

You successfully reached the end of this rather long and detailed tutorial — congrats!.

While Coolify makes self-hosting seamless and CrowdSec adds a powerful layer of protection, combining the two requires careful attention to how logs are exposed, how proxies handle requests, and which services should be monitored directly.

If you’re using Coolify to deploy your stack, adding CrowdSec to the mix gives you a modern, flexible way to defend against abusive IPs and unwanted traffic, no matter where it comes from.

I hope this guide has given you a solid starting point. As both Coolify and CrowdSec evolve, we’ll continue to improve this integration and make it even easier to secure your services with minimal friction.
If you have feedback or encounter any issues or problems then please seek community support via our Discord or Discourse. And if you want to see this become a one-click template do let us know!

WRITTEN BY

You may also like

how to mitigate distributed denial of service (ddos)
Tutorial

How to Mitigate Distributed Denial of Service (DDoS) Attacks

Read along for a general introduction to DDoS as a concept, the different types of DDoS attacks, and how to successfully mitigate them.

advanced application security with the crowdsec waf
Ambassador Post

Implementing the CrowdSec WAF for Advanced Web Application Security

Transform your Security Engine into a WAF with this get-started guide and learn how to integrate and configure the AppSec Component with NGINX on Debian 12.

how to waste attacker resources and protect applications
Tutorial

How to Waste Attacker Resources and Protect Your Applications in One Go

Discover the power of SpiderTrap Sinkholes combined with CrowdSec in this step-by-step guide to protect your applications and exhaust attackers’ resources.