Securely Access Your CrowdSec Manager Anywhere Using Tailscale (and Lock It Down with ACLs)
why tailscale
- Backup Stratagy: Even if pangolin goes down and you don’t have immediate access to your computer you can restart and diagnose pangolin and get your home access back..
If you are running CrowdSec in a Docker environment, you already know how vital it is for securing your infrastructure. But when it comes to checking your manager dashboard or logs, you face a common dilemma: how do you access it remotely without opening vulnerable ports to the public internet?
The answer is Tailscale.
By using a “Sidecar” pattern in Docker Compose, we can seamlessly attach a CrowdSec manager container directly to your private Tailscale network (Tailnet). This gives you secure, encrypted access to your container from any device in the world, while perfectly preserving your local network routing and Traefik configurations.
Here is exactly how to set it up—and how to lock it down using strict Role-Based Access Control (RBAC).
Part 1: The Docker Compose Configuration
Prerequisites
Before diving into the Compose file, you will need:
- Docker and Docker Compose installed on your host.
- A free Tailscale account.
- A Tailscale Auth Key (Generate a reusable, non-expiring key in your Tailscale Admin console under Settings > Keys).
Deploying the Tailscale Sidecar
The magic of this setup lies in the network_mode: service:tailscale directive. Instead of putting our CrowdSec manager on the standard Docker network, we are hiding it behind a dedicated Tailscale container.
Here is the docker-compose.yml file you need:
services:
# 1. The Tailscale Sidecar
tailscale:
image: tailscale/tailscale:latest
container_name: tailscale-crowdsec
hostname: crowdsec-manager-ts # This name appears in your Tailscale dashboard
environment:
- TS_AUTHKEY=tskey-auth-xxxxx # Replace with your actual Auth Key!
- TS_STATE_DIR=/var/lib/tailscale
volumes:
- tailscale-data:/var/lib/tailscale
- /dev/net/tun:/dev/net/tun
cap_add:
- net_admin
- sys_module
ports:
- "127.0.0.1:8080:8080" # Preserves safe localhost access on the host
networks:
pangolin:
aliases:
- crowdsec-manager # Crucial: Allows Traefik/other containers to route traffic here
restart: unless-stopped
# 2. Your CrowdSec Manager
crowdsec-manager:
image: hhftechnology/crowdsec-manager:latest
container_name: crowdsec-manager
network_mode: service:tailscale # Merges this container's network with Tailscale
depends_on:
- tailscale
restart: unless-stopped
environment:
- PORT=8080
- ENVIRONMENT=production
- TRAEFIK_DYNAMIC_CONFIG=/etc/traefik/dynamic_config.yml
- TRAEFIK_CONTAINER_NAME=traefik
- TRAEFIK_STATIC_CONFIG=/etc/traefik/traefik_config.yml
- CROWDSEC_METRICS_URL=http://crowdsec:6060/metrics
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /root/config:/app/config
- /root/docker-compose.yml:/app/docker-compose.yml
- ./backups:/app/backups
- ./data:/app/data
networks:
pangolin:
external: true
volumes:
tailscale-data:
Why We Did It This Way
- Backup Stratagy: Even if pangolin goes down and you don’t have immediate access to your computer you can restart and diagnose pangolin and get your home access back..
- Zero Open Ports: Your CrowdSec manager is completely invisible to the public internet. It only talks to Tailscale.
- No Broken Routing: By giving the Tailscale container the network alias
crowdsec-manager, other containers on yourpangolinnetwork (like Traefik) can still talk to it using the hostname they always have. Nothing breaks. - Persistent Authentication: The
tailscale-datavolume ensures that when you restart or update your containers, your node doesn’t forget its Tailscale identity.
How to Access Your Container
Once you run docker-compose up -d, your container will join your Tailnet. You now have three distinct ways to access it:
- From Anywhere in the World (via Tailscale): Navigate to the MagicDNS name:
http://crowdsec-manager-ts:8080 - From the Local Server (Localhost): The port mapping in the Compose file specifically binds to your local loopback address:
http://127.0.0.1:8080 - From Inside Docker: Other containers use the internal Docker network alias:
http://crowdsec-manager:8080
Part 2: Advanced Security - Hardening Access with Tailscale ACLs
If you are running a multi-user Tailnet (such as a shared homelab or a corporate team environment), a “default-allow” policy isn’t enough. You need to restrict exactly who can access your CrowdSec manager.
Tailscale manages network traffic rules using Access Control Lists (ACLs) defined in HuJSON. To strictly control access to the CrowdSec container, we will transition from identity-based human access to Role-Based Access Control (RBAC) using Tailscale groups and tags.
Step 1: Conceptualizing the Access Model
To enforce the principle of least privilege, we must implement the following architecture:
- Groups: Define a specific group of human users (e.g.,
group:secops) authorized to view the dashboard. - Tags: Servers and containers should not authenticate as human users. We will assign a machine tag (
tag:crowdsec) to the Docker container. - Policies: Write a strict ACL rule that explicitly permits traffic only from
group:secopstotag:crowdsecon port8080.
Step 2: Preparing the Tailscale Auth Key and Tags
Before modifying the ACLs, we need to ensure the CrowdSec Tailscale sidecar is properly tagged.
- Go to the Access Controls page in your Tailscale Admin Console.
- Define the tag owner so your security team has the authority to assign it:
"tagOwners": {
"tag:crowdsec": ["group:secops"]
},
- Generate a new Auth Key in the Tailscale dashboard, and explicitly apply the
tag:crowdsectag to the key during creation. - Replace the
TS_AUTHKEYin yourdocker-compose.ymlwith this new tagged key. When the container boots, it identifies to the control plane as a tagged machine rather than inheriting the identity of the user who created the key.
Step 3: Defining the ACL Rules (HuJSON)
Navigate to your Tailscale Admin Console’s Access Controls tab. Below is the required HuJSON configuration to lock down the container:
{
// 1. Define your administrative groups
"groups": {
"group:secops": [
"admin.user@yourdomain.com",
"auditor@yourdomain.com"
]
},
// 2. Define who is allowed to deploy infrastructure with specific tags
"tagOwners": {
"tag:crowdsec": ["group:secops"]
},
// 3. Define the routing rules (ACLs)
"acls": [
// Enforce explicit access: Only SecOps can hit the CrowdSec dashboard via port 8080
{
"action": "accept",
"src": ["group:secops"],
"dst": ["tag:crowdsec:8080"]
},
// (Optional) Permit the CrowdSec manager to initiate outbound connections to the internet
// via an exit node, or to other internal services for log ingestion over Tailscale.
{
"action": "accept",
"src": ["tag:crowdsec"],
"dst": ["autogroup:internet:*"]
}
]
}
Technical Breakdown of the ACL Rule
"action": "accept": Tailscale operates on a default-deny paradigm once strict rules are applied. You only writeacceptrules."src": ["group:secops"]: Because this is bound to a group, Tailscale’s control plane will verify the cryptographic identity of the source node against the user’s current session state."dst": ["tag:crowdsec:8080"]: This explicitly binds the rule to the Layer 4 port (8080). Even if a user in thesecopsgroup attempts to hit port22(SSH) or80, the control plane’s packet filter will silently drop the packets.
Step 4: Verification
Once applied, Tailscale pushes the updated packet filtering rules to all nodes almost instantly via the WireGuard tunnels.
- If a user not in
group:secopsattempts to navigate tohttp://crowdsec-manager-ts:8080, the TCP connection will immediately time out. - Your local machine interactions (e.g., hitting
127.0.0.1:8080from the host OS) remain entirely unaffected, as that traffic routes through the local Linux network namespace, bypassing the Tailscale WireGuard interface entirely.
Wrapping Up
By deploying Tailscale as a sidecar and enforcing strict ACLs, you get the absolute best of both worlds: robust local network compatibility and locked-down, zero-trust remote access. Spin it up, connect your devices, and enjoy highly secure access to your infrastructure from anywhere!