Building a Multi-Container CrowdSec Hub on Proxmox LXC
A complete technical walkthrough of migrating from standalone security to a centralized CrowdSec Hub-and-Spoke architecture.

Managing security across multiple Proxmox LXC containers quickly becomes cumbersome. Originally, running standalone Fail2ban or CrowdSec instances inside every individual LXC container meant parsing logs on 15 separate instances, maintaining duplicate blocklists, and wasting CPU resources on redundant threat processing.
A significantly cleaner pattern is implementing a CrowdSec hub-and-spoke model: deploying one central Local API (LAPI) node to manage security decisions, while the remaining containers operate as lightweight agents and enforcement bouncers.
How the Architecture Works
Rather than executing a full CrowdSec engine inside every container, responsibilities are logically separated:
- The Hub (LAPI Server): A dedicated, lightweight LXC container running the CrowdSec Local API daemon. It aggregates threat intelligence from the global CrowdSec network, processes incoming security events, and maintains the authoritative blocklist.
- The Spokes (Agents & Bouncers): Containers running application workloads (such as Nginx Proxy Manager, Nextcloud, or Gitea). They execute the lightweight CrowdSec agent to forward log events to the Hub, or query the Hub's LAPI to drop malicious traffic at the firewall or reverse proxy layer.
Implementation Steps
1. Setting Up the Central Hub
Provision a fresh Debian or Ubuntu LXC container in Proxmox to serve as the hub. Install CrowdSec:
curl -s https://install.crowdsec.net | sudo sh
sudo apt-get install -y crowdsec
By default, CrowdSec binds its Local API to 127.0.0.1:8080. To allow spoke containers on your internal subnet to connect, modify /etc/crowdsec/config.yaml:
api:
server:
listen_uri: 0.0.0.0:8080
Restart CrowdSec to apply the changes:
sudo systemctl restart crowdsec
2. Registering Spoke Machines
On the Hub container, create machine credentials for each spoke (for instance, your Nginx Proxy Manager container):
sudo cscli machines add nginx-proxy-spoke --auto
Save the generated password and API key.
On the spoke container, install the CrowdSec agent. Disable its local LAPI service so it does not evaluate decisions locally, and update /etc/crowdsec/config.yaml to point the agent to your Hub's IP address:
api:
client:
insecure_skip_verify: false
credentials_path: /etc/crowdsec/local_api_credentials.yaml
Update /etc/crowdsec/local_api_credentials.yaml with the Hub's LAPI connection details:
url: http://<HUB_IP>:8080
login: nginx-proxy-spoke
password: <GENERATED_PASSWORD>
Finally, verify the agent connection on the Hub:
sudo cscli machines list
3. Attaching Bouncers
Install the appropriate bouncer plugin on each spoke container (such as crowdsec-firewall-bouncer or the Nginx Proxy Manager bouncer plugin). Register the bouncer with the Hub to receive real-time blocklist updates:
sudo cscli bouncers add nginx-proxy-bouncer
Results
Decoupling log parsing from threat analysis reduced total security-related CPU consumption across the Proxmox cluster by roughly 60%. Crucially, threat mitigation is now synchronized across the entire network: if an IP triggers a brute-force threshold on Nextcloud, it is immediately blocked across Nginx Proxy Manager and all other exposed services before any further request attempts occur.
Need help architecting your Proxmox infrastructure?
Let's talk