vault backup: 2026-03-13 20:01:15

This commit is contained in:
Vincent Verbruggen
2026-03-13 20:01:15 +01:00
parent 33c80f4afd
commit 7a047821e5
3 changed files with 494 additions and 1 deletions

View File

@@ -0,0 +1,491 @@
---
created: 2026-03-13
updated: 2026-03-13
---
# CrowdSec Setup with Traefik
## Overview
CrowdSec protects all services behind Traefik by analyzing access logs and blocking malicious IPs. Combined with disabling Gitea SSH (port 2222), all public traffic flows through Traefik where CrowdSec can inspect and block it.
```
Internet (Port 80/443 only)
Router Port Forwarding
┌──────────────────────────────────────────┐
│ Traefik │
│ ┌──────────────────────────────┐ │
│ │ CrowdSec Bouncer Middleware │ ← blocks│
│ └──────────────┬───────────────┘ │
│ │ allowed traffic │
└─────────────────┼────────────────────────┘
traefik_proxy network
┌─────────┼─────────┐
↓ ↓ ↓
Gitea Servarr Future
Services
CrowdSec Engine ← reads Traefik access logs
Community Blocklists (optional)
```
## Prerequisites
- Working Traefik setup (see [[Traefik Multi-Stack Setup]])
- Router port forwarding for 80/443 only (remove 2222)
---
## Step 1: Disable Gitea SSH and Switch to HTTPS Git
### 1.1 Close Port 2222
Remove the port 2222 forwarding rule from your router. This immediately stops all SSH brute-force attempts.
### 1.2 Remove SSH Port from Gitea Stack
Edit `/mnt/tank/stacks/gitea/docker-compose.yml`:
- Remove the `ports` section (or just the `2222:22` mapping)
- Optionally add `GITEA__server__DISABLE_SSH=true`
```yaml
services:
gitea:
image: gitea/gitea:latest
container_name: gitea
restart: unless-stopped
environment:
- USER_UID=1000
- USER_GID=1000
- GITEA__database__DB_TYPE=sqlite3
- GITEA__server__DOMAIN=git.vv.nl
- GITEA__server__ROOT_URL=https://git.vv.nl
- GITEA__server__DISABLE_SSH=true
- GITEA__service__DISABLE_REGISTRATION=true
networks:
- traefik_proxy
- gitea_internal
volumes:
- ./data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
# No ports exposed - Traefik handles HTTPS, SSH disabled
labels:
- "traefik.enable=true"
- "traefik.docker.network=traefik_proxy"
- "traefik.http.routers.gitea.rule=Host(`git.vv.nl`)"
- "traefik.http.routers.gitea.entrypoints=websecure"
- "traefik.http.routers.gitea.tls.certresolver=cloudflare"
- "traefik.http.services.gitea.loadbalancer.server.port=3000"
```
### 1.3 Restart Gitea
```bash
cd /mnt/tank/stacks/gitea
docker compose down
docker compose up -d
```
### 1.4 Set Up HTTPS Git Authentication
On Gitea, create a personal access token:
1. Go to `https://git.vv.nl/user/settings/applications`
2. Create a new token with `repository` scope
3. Save the token securely
On your local machines, configure git to use HTTPS:
```bash
# Update existing remotes from SSH to HTTPS
git remote set-url origin https://git.vv.nl/username/repo.git
# Store credentials so you don't have to enter the token every time
git config --global credential.helper store
# On first push/pull, use your Gitea username and the token as password
git push origin main
# Username: your-gitea-username
# Password: your-personal-access-token
```
Alternatively, use the token directly in the URL (less secure, stored in git config):
```bash
git remote set-url origin https://username:TOKEN@git.vv.nl/username/repo.git
```
---
## Step 2: Enable Traefik Access Logs
CrowdSec needs Traefik's access logs to detect malicious behavior. Edit `/mnt/tank/stacks/traefik/traefik.yml` and add:
```yaml
accessLog:
filePath: "/var/log/traefik/access.log"
bufferingSize: 100
# ... rest of your existing config (api, entryPoints, providers, certificatesResolvers)
```
Then update `/mnt/tank/stacks/traefik/docker-compose.yml` to mount the log directory:
```yaml
services:
traefik:
# ... existing config ...
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik.yml:/traefik.yml:ro
- ./letsencrypt:/letsencrypt
- traefik-logs:/var/log/traefik # Add this line
volumes:
traefik-logs:
name: traefik-logs # Named volume, shared with CrowdSec
```
Restart Traefik:
```bash
cd /mnt/tank/stacks/traefik
docker compose down
docker compose up -d
```
---
## Step 3: Deploy CrowdSec
Since CrowdSec is tightly coupled to Traefik (reads its logs, provides its middleware), it lives in the Traefik stack.
### 3.1 Create CrowdSec Acquis Config
Create the log acquisition config:
```bash
mkdir -p /mnt/tank/stacks/traefik/crowdsec
```
Create `/mnt/tank/stacks/traefik/crowdsec/acquis.yaml`:
```yaml
filenames:
- /var/log/traefik/*
labels:
type: traefik
```
### 3.2 Add CrowdSec to Traefik Stack
Edit `/mnt/tank/stacks/traefik/docker-compose.yml` to add the CrowdSec engine and bouncer:
```yaml
version: '3.8'
networks:
traefik_proxy:
name: traefik_proxy
driver: bridge
volumes:
traefik-logs:
name: traefik-logs
crowdsec-db:
name: crowdsec-db
crowdsec-config:
name: crowdsec-config
services:
traefik:
image: traefik:v2.10
container_name: traefik
restart: unless-stopped
depends_on:
- crowdsec-bouncer
security_opt:
- no-new-privileges:true
networks:
- traefik_proxy
ports:
- "80:80"
- "443:443"
environment:
- TZ=Europe/Amsterdam
- CF_DNS_API_TOKEN=your-cloudflare-api-token
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik.yml:/traefik.yml:ro
- ./letsencrypt:/letsencrypt
- traefik-logs:/var/log/traefik
labels:
- "traefik.enable=true"
# Dashboard
- "traefik.http.routers.traefik.rule=Host(`traefik.vv.nl`)"
- "traefik.http.routers.traefik.entrypoints=websecure"
- "traefik.http.routers.traefik.tls.certresolver=cloudflare"
- "traefik.http.routers.traefik.service=api@internal"
- "traefik.http.routers.traefik.middlewares=traefik-auth,crowdsec@docker"
- "traefik.http.middlewares.traefik-auth.basicauth.users=admin:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/"
crowdsec:
image: crowdsecurity/crowdsec:latest
container_name: crowdsec
restart: unless-stopped
networks:
- traefik_proxy
environment:
- TZ=Europe/Amsterdam
# Install the Traefik log parser and HTTP scenarios
- COLLECTIONS=crowdsecurity/traefik crowdsecurity/http-cve crowdsecurity/base-http-scenarios
# Enroll with CrowdSec Console (optional, get key from app.crowdsec.net)
# - ENROLL_KEY=your-enrollment-key
volumes:
- crowdsec-db:/var/lib/crowdsec/data
- crowdsec-config:/etc/crowdsec
- traefik-logs:/var/log/traefik:ro # Read Traefik logs
- ./crowdsec/acquis.yaml:/etc/crowdsec/acquis.yaml:ro
crowdsec-bouncer:
image: fbonalair/traefik-crowdsec-bouncer:latest
container_name: crowdsec-bouncer
restart: unless-stopped
depends_on:
- crowdsec
networks:
- traefik_proxy
environment:
- CROWDSEC_BOUNCER_API_KEY=GENERATE_THIS # See step 3.3
- CROWDSEC_AGENT_HOST=crowdsec:8080
- GIN_MODE=release
labels:
- "traefik.enable=true"
# Define the CrowdSec middleware (forwardAuth to the bouncer)
- "traefik.http.middlewares.crowdsec.forwardauth.address=http://crowdsec-bouncer:8080/api/v1/forwardAuth"
- "traefik.http.middlewares.crowdsec.forwardauth.trustForwardHeader=true"
```
### 3.3 Generate the Bouncer API Key
First, bring up CrowdSec alone to generate the API key:
```bash
cd /mnt/tank/stacks/traefik
# Start only CrowdSec first
docker compose up -d crowdsec
# Wait a few seconds for it to initialize, then generate a bouncer API key
docker exec crowdsec cscli bouncers add traefik-bouncer
# Copy the generated API key and put it in the docker-compose.yml
# Replace GENERATE_THIS with the actual key
```
Then start everything:
```bash
docker compose up -d
```
### 3.4 Verify CrowdSec is Working
```bash
# Check CrowdSec is parsing logs
docker exec crowdsec cscli metrics
# Check installed collections
docker exec crowdsec cscli collections list
# Check active decisions (bans)
docker exec crowdsec cscli decisions list
# Check bouncer is registered
docker exec crowdsec cscli bouncers list
```
---
## Step 4: Apply CrowdSec Middleware to All Services
For each service behind Traefik, add `crowdsec@docker` to its middleware chain.
### Gitea
In `/mnt/tank/stacks/gitea/docker-compose.yml`, add the middleware label:
```yaml
labels:
- "traefik.enable=true"
- "traefik.docker.network=traefik_proxy"
- "traefik.http.routers.gitea.rule=Host(`git.vv.nl`)"
- "traefik.http.routers.gitea.entrypoints=websecure"
- "traefik.http.routers.gitea.tls.certresolver=cloudflare"
- "traefik.http.routers.gitea.middlewares=crowdsec@docker" # Add this
- "traefik.http.services.gitea.loadbalancer.server.port=3000"
```
### Any Future Service
Same pattern - add `crowdsec@docker` to the middlewares label:
```yaml
- "traefik.http.routers.service-name.middlewares=crowdsec@docker"
```
### Multiple Middlewares
Chain middlewares with commas:
```yaml
- "traefik.http.routers.traefik.middlewares=traefik-auth,crowdsec@docker"
```
---
## Step 5: Optional - Enroll in CrowdSec Console
The CrowdSec Console at `app.crowdsec.net` provides:
- Community blocklists (block known-bad IPs before they hit your server)
- Dashboard to visualize attacks
- Alert notifications
To enroll:
1. Create a free account at `https://app.crowdsec.net`
2. Get your enrollment key from the console
3. Add to docker-compose.yml: `ENROLL_KEY=your-key`
4. Or enroll manually: `docker exec crowdsec cscli console enroll your-key`
---
## Management Commands
```bash
# View current bans
docker exec crowdsec cscli decisions list
# Manually ban an IP
docker exec crowdsec cscli decisions add --ip 176.120.22.17 --reason "SSH brute force"
# Unban an IP (if you accidentally ban yourself)
docker exec crowdsec cscli decisions delete --ip YOUR_IP
# View metrics (parsed logs, scenarios triggered)
docker exec crowdsec cscli metrics
# View alerts
docker exec crowdsec cscli alerts list
# Update CrowdSec hub (scenarios, parsers)
docker exec crowdsec cscli hub update
docker exec crowdsec cscli hub upgrade
```
---
## Troubleshooting
### Bouncer Not Blocking
```bash
# Verify bouncer is registered
docker exec crowdsec cscli bouncers list
# Check bouncer logs
docker logs crowdsec-bouncer
# Test with a manual ban on a test IP
docker exec crowdsec cscli decisions add --ip 1.2.3.4 --reason "test"
# Then try to access your services from that IP
docker exec crowdsec cscli decisions delete --ip 1.2.3.4
```
### CrowdSec Not Parsing Logs
```bash
# Check if acquisition is working
docker exec crowdsec cscli metrics
# Look for "traefik" in the acquisition metrics
# If zero lines parsed, check the log path and acquis.yaml
# Verify Traefik is writing logs
docker exec traefik ls -la /var/log/traefik/
# Check CrowdSec logs for errors
docker logs crowdsec
```
### Locked Out of Your Own Services
If you accidentally ban your own IP:
```bash
# SSH into TrueNAS (SSH is on the host, not through Traefik)
ssh user@truenas-local-ip
# Remove the ban
docker exec crowdsec cscli decisions delete --ip YOUR_IP
# Whitelist your IP to prevent future bans
docker exec crowdsec cscli parsers install crowdsecurity/whitelists
# Edit the whitelist config
docker exec -it crowdsec vi /etc/crowdsec/parsers/s02-enrich/whitelists.yaml
```
To permanently whitelist your IP, create `/mnt/tank/stacks/traefik/crowdsec/whitelist.yaml`:
```yaml
name: mywhitelists
description: "My personal whitelist"
whitelist:
reason: "My home/office IP"
ip:
- "YOUR_HOME_IP"
# Add any other trusted IPs
```
Mount it in the CrowdSec container:
```yaml
volumes:
- ./crowdsec/whitelist.yaml:/etc/crowdsec/parsers/s02-enrich/mywhitelists.yaml:ro
```
---
## Port Forwarding (Updated)
After this setup, your router should only forward:
| External Port | Internal Port | Protocol | Service |
|--------------|---------------|----------|---------|
| 80 | 80 | TCP | Traefik HTTP (redirects to HTTPS) |
| 443 | 443 | TCP | Traefik HTTPS (CrowdSec protected) |
Port 2222 is **no longer forwarded**.
---
## Architecture Summary
- All public traffic enters through ports 80/443 only
- Traefik terminates TLS and routes requests
- CrowdSec bouncer middleware checks every request against the ban list
- CrowdSec engine continuously parses Traefik access logs for malicious patterns
- Community blocklists proactively block known-bad IPs
- No direct port exposure for any backend service
---
## Related
- [[Traefik Multi-Stack Setup]] - Base Traefik configuration
- [[Security TODO]] - Other security improvements
- [[Quick Reference]] - Common management commands

View File

@@ -38,7 +38,8 @@
### Planned:
- [ ] Investigate Cloudflare Tunnel
- [ ] Research Pangolin
- [ ] Add Fail2ban for brute force protection
- [x] ~~Add Fail2ban for brute force protection~~ → Replaced by CrowdSec (see [[CrowdSec Setup]])
- [x] Close port 2222, disable Gitea SSH, use HTTPS git (see [[CrowdSec Setup#Step 1]])
- [ ] Implement Traefik rate limiting middleware
- [ ] Set up IP whitelisting for admin interfaces
- [ ] Regular security audits of exposed services

View File

@@ -38,6 +38,7 @@ Documentation for TrueNAS home server setup, configuration, and services.
**Detailed Guides:**
- [[Traefik Multi-Stack Setup]] - One Traefik instance for multiple service stacks
- [[CrowdSec Setup]] - CrowdSec IPS protecting all services via Traefik middleware
- [[Integrating Servarr Stack with Traefik]] - How to connect your existing Servarr stack
- [[Docker Gitea with Traefik]] - Docker deployment with Traefik reverse proxy
- [[Gitea Setup]] - Alternative: TrueNAS Apps installation (not using this)