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!