Skip to main content

Preface

Cloudways is a managed cloud hosting platform that makes it easy to host websites and applications across different cloud providers.

It gives you SSH access, but with limited permissions.

However, you can still run the Security Engine on Cloudways to enable behavior detection for your services (Nginx and Apache) and use our WordPress plugin to apply remediation, including the blocklist feature. This guide is more detailed than others because it covers the specific steps required for integrating CrowdSec with Cloudways.

We'll walk you through the following steps:

  1. Install CrowdSec using the static build
  2. Set up acquisition and detection collections
  3. Run behavior detection on your past logs to see what would have been flagged
  4. Make CrowdSec run as a user-level service
  5. Connect it to the WordPress plugin to block detected attackers

Install CrowdSec from the static build

In this section, we'll get the latest static build of CrowdSec, build the folder hierarchy with the slightly tweaked test_env script and create the necessary config for the Local API and Central API.

Setup CrowdSec static build

For this setup we'll put CrowdSec in the /home/master/crowdsec folder.

Get the static build

  • Go to the latest release page
  • Scroll down past the changelog, in the Assets section copy the link to the crowdsec-release.tgz file
  • ensure you are within the /home/master folder
cd /home/master
  • download it in your /home/master folder, example:
wget https://github.com/crowdsecurity/crowdsec/releases/download/v1.6.3/crowdsec-release.tgz
  • Extract the archive:
tar -xvzf crowdsec-release.tgz
  • Rename the extracted folder to crowdsec:
mv crowdsec-v1.6.3 crowdsec

Create the folder hierarchy

  • cd into the crowdsec folder:
cd crowdsec
  • Tweak the test_env script to create the necessary folders and config:
sed -i 's|BASE="./tests"|BASE="/home/master/crowdsec"|' test_env.sh
  • Run the script:
./test_env.sh
  • Check one config file symlink to make sure the tweak worked:
ls -la config/parsers/s00-raw/syslog-logs.yaml 

Should output config/parsers/s00-raw/syslog-logs.yaml -> /home/master/crowdsec/config/hub/parsers/s00-raw/crowdsecurity/syslog-logs.yaml

Create the config

We'll take the template config, update a few ports to avoid conflicts and setup the Local API and Central API.

  • We'll use the dev.yml template to create our config.yaml:
mv dev.yml config.yaml

Update the configuration

/home/master/crowdsec/config.yaml

We need to make alterations to the config file for this static install and to avoid conflicts and setup the Local API.

  • First, replace all* ./ with /home/master/crowdsec/ *in the config.yaml file
sed -i 's|./|/home/master/crowdsec/|g' config.yaml

Open the /home/master/crowdsec/config.yaml with your favourite terminal editor and make the following changes:

  • Update log_media and add log dir
common:
log_media: file ## Alter this line from stdout to file
log_dir: ./logs ## Add this line, ensure it indented correctly
  • Then uncomment and replace the hubdir with the correct path:
[...]
hub_dir: /home/master/crowdsec/config/hub
  • Finally, change the local API port to 19443 in order to avoid conflicts
[...]
api:
server:
listen_uri: 127.0.0.1:19443

Create some quality of life aliases

In order to make the command line easier to use, we'll create some aliases for the CrowdSec CLI and crowdsec itself. This way you won't have to call it from the full path with the config param each time.

  • Add the following to your* /home/master/.bash_aliases* file:
alias cscli="/home/master/crowdsec/cscli -c /home/master/crowdsec/config.yaml"
alias crowdsec="/home/master/crowdsec/crowdsec -c /home/master/crowdsec/config.yaml"
  • Reload your bash profile:
source /home/master/.bashrc

Init CAPI (Central API) credentials

We can initilized the CAPI credentials with the following command:

cscli capi register

This will generate /home/master/crowdsec/config/online_api_credentials.yaml make sure to keep this file safe.

warning

The output will instruct you to restart the service, but we'll do that later.

Reset LAPI (Local API) credentials

  • Remove the existing machine and create a new one in auto:
cscli machines list  //ignore the warning it's normal for now
  • You should see something like this
────────────────────────────────────────────────────────────────────────────────────────
Name IP Address Last Update Status Version OS Auth Type Last Heartbeat
────────────────────────────────────────────────────────────────────────────────────────
test 2024-09-12T10:04:52Z ✔️ ? password ⚠️ -
────────────────────────────────────────────────────────────────────────────────────────
  • Delete the test machine
cscli machines delete test_env
  • Create a new default one with --force to override the existing credentials file
cscli machines add my_logprocessor --auto --force 
  • C that the credential file has the proper port : cat ./config/local_api_credentials.yaml
url: http://127.0.0.1
login: my_logprocessor
password: 321QSd54QERG321sq54AZEqs45AZDQSd654z65fps

Setup acquisitions and detection collections

Acquisition configuration indicates to CrowdSec what log files it should look at.
The Detection collections include parsers config and bad behavior detection scenarios for given services.

In our case we'll look at the nginx logs and apache2 logs.

  • We'll use wildcards to work with any application name of your application folder: ls /home/master/applications
  • Replace the content of the config/acquis.yaml file (with you editor of choice) with the following:
filenames:
- /home/master/applications/**/logs/nginx_*.log
labels:
type: nginx
---
filenames:
- /home/master/applications/**/logs/apache_*.log
labels:
type: apache2

Getting collections

Now we'll install the collections for nginx and apache2.
You can find our catalog on our Hub.

  • Run the following command to install the collections:
cscli collections install crowdsecurity/nginx crowdsecurity/apache2

Making the collections auto update

CrowdSec collection often get updated with the behavior detections.
CrowdSec teams create and currate community scenarios allowing its users to benefit from the latest vulnerabilities detection. We'll allow hub auto-update with a cron:

  • Create a hub_update.sh file in the crowdsec folder:
#!/bin/sh

test -x /home/master/crowdsec/cscli || exit 0

# splay hub upgrade and crowdsec reload
sleep "$(seq 1 300 | shuf -n 1)"

/home/master/crowdsec/cscli -c /home/master/crowdsec/config.yaml --error hub update

upgraded=$(/home/master/crowdsec/cscli -c /home/master/crowdsec/config.yaml --error hub upgrade)
if [ -n "$upgraded" ]; then
systemctl --user reload crowdsec
fi

exit 0
  • Add it to crontab, every day at 6 for example
0 6 * * * /home/master/crowdsec/hub_update.sh

Make sure log rotation not breaking acquisition

As CrowdSec is not running as root in our current context, there could be some race conditions with log rotation file creation making the acquisition fail. Future versions of CrowdSec might address this issue, but for now, we can use a simple script to ensure the acquisition is not broken.

  • Create a script to ensure the acquisition is not broken
vi /home/master/crowdsec/check_rotation.sh
#!/bin/bash

# Set the path to your CrowdSec log file
LOG_FILE="/home/master/crowdsec/logs/crowdsec.log"

# Get today's date in the format used in the logs (UTC time)
TODAY=$(date -u +"%Y-%m-%d")

# Define the error pattern to search for
ERROR_PATTERN='level=warning .* died : Unable to open file .*: permission denied'

# Search for the error in today's logs
if grep "$TODAY" "$LOG_FILE" | grep -qE "$ERROR_PATTERN"; then
# Log the action
echo "$(date): Error found, restarting CrowdSec service" >> /home/master/crowdsec/logs/crowdsec_rotation_fail.log

# Restart the CrowdSec service
systemctl restart --user crowdsec

# Log the completion
echo "$(date): CrowdSec service restarted successfully" >> /home/master/crowdsec/logs/crowdsec_rotation_fail.log
else
# Log that no action was taken
echo "$(date): No error found, no action taken" >> /home/master/crowdsec/logs/crowdsec_rotation_fail.log
fi

Make the check run every day at 00:01

1 0 * * * /home/master/crowdsec/check_rotation.sh

Run a behavior detection on your past logs to see what it would have found

We can run the behavior detection on the past logs to catch alerts that happened in the past.
We'll run it on the nginx access logs and the first archive of nginx access logs (previous day)

  • Run the behavior detection on the past logs:
./crowdsec -c config.yaml -dsn file:///home/master/applications/\*\*/logs/nginx_*.access.log --type nginx --no-api
  • Note that dsn parameter take the file://*/ protocol and an absolute path
  • After you ran the detection, detected alerts should be listed in:
cscli alerts list

Make CrowdSec service run at user level

We want CrowdSec to run in the background and start at boot.
For this we'll add a systemd service in the user level.

Create the systemd service for user

  • At the time of writting (for v1.6.3) you can use the following content:
  • Create and edit ~/.config/systemd/user/crowdsec.service
[Unit]
Description=Crowdsec agent

[Service]
WorkingDirectory=/home/master/crowdsec
Type=notify
Environment=LC_ALL=C LANG=C
ExecStartPre=/home/master/crowdsec/crowdsec -c /home/master/crowdsec/config.yaml -t -error
ExecStart=/home/master/crowdsec/crowdsec -c /home/master/crowdsec/config.yaml
#ExecStartPost=/bin/sleep 0.1
ExecReload=/home/master/crowdsec/crowdsec -c /home/master/crowdsec/config.yaml -t -error
ExecReload=/bin/kill -HUP $MAINPID
Restart=always
RestartSec=60

[Install]
WantedBy=multi-user.target

Enable the service to run at boot

For a user level process to keep running after you close the connection we need to activate the "linger"

  • Run the following command:
loginctl enable-linger
  • Then have systemctl reload and run crowdsec
systemctl --user daemon-reload
systemctl --user enable --now crowdsec
  • Check the status of the service
systemctl --user status crowdsec
  • In the future you can systemctl --user start crowdsec or stop or restart

Checking that CrowdSec works

We ran a behavior detection on the past logs so we might already have acquisition and parsing metrics. But to check that its working, you can visit your website

  • It should generate lines of logs
  • As soon as new log lines arrive in any of those:
    • You should see the acquisition metrics appear/update
    • And the resulting parser acquisition and metrics
cscli metrics -c config.yaml
  • looking something like
Acquisition Metrics:
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────┬────────────┬──────────────┬────────────────┬────────────────────────┬───────────────────╮
│ Source │ Lines read │ Lines parsed │ Lines unparsed │ Lines poured to bucket │ Lines whitelisted │
├──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼────────────┼──────────────┼────────────────┼────────────────────────┼───────────────────┤
│ file:/home/master/applications/abcdefghij/logs/apache_wordpress-1211499-4678369.cloudwaysapps.com.access.log │ 11 │ - │ - │ - │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────┴────────────┴──────────────┴────────────────┴────────────────────────┴───────────────────╯

[...]

Parser Metrics:
╭──────────────────────────────────┬──────┬────────┬──────────╮
│ Parsers │ Hits │ Parsed │ Unparsed │
├──────────────────────────────────┼──────┼────────┼──────────┤
│ child-crowdsecurity/apache2-logs │ 11 │ - │
│ child-crowdsecurity/http-logs │ 33 │ - │
│ crowdsecurity/apache2-logs │ 11 │ - │
│ crowdsecurity/dateparse-enrich │ 11 │ - │
│ crowdsecurity/geoip-enrich │ 11 │ - │
│ crowdsecurity/http-logs │ 11 │ - │
│ crowdsecurity/non-syslog │ 11 │ - │
╰──────────────────────────────────┴──────┴────────┴──────────╯

Bind it to the WP plugin to block the detected attackers

Now that we have CrowdSec running and detecting bad behaviors.
Alerts are raised and decisions to block bad actors are stored in the local DB.
To actually apply a remediation and ban the attackers from your website you need:

  • To create a bouncer API key:
cscli bouncers add my_wp_bouncer
  • You should see something like this:
API key for 'my_wp_bouncer':

OI8BQQqMcasoeuxK2g5lMSHPLVkH1tARqLIW0HS3cIY

Please keep this key since you will not be able to retrieve it!