- Added TestMigrateCommand_Succeeds to validate migration functionality. - Introduced TestStartupVerification_MissingTables to ensure proper handling of missing security tables. - Updated crowdsec_startup.go to log warnings for missing SecurityConfig table. - Enhanced documentation for database migrations during upgrades, including steps and expected outputs. - Created a detailed migration QA report outlining testing results and recommendations. - Added troubleshooting guidance for CrowdSec not starting after upgrades due to missing tables. - Established a new plan for addressing CrowdSec reconciliation failures, including root cause analysis and proposed fixes.
12 KiB
CrowdSec Control Migration Guide
What Changed in Version 2.0
Before (v1.x): CrowdSec was controlled by environment variables like CHARON_SECURITY_CROWDSEC_MODE.
After (v2.x): CrowdSec is controlled via the GUI toggle in the Security dashboard, matching how WAF, ACL, and Rate Limiting work.
Why This Changed
The Problem with Environment Variables
In version 1.x, CrowdSec had inconsistent control:
- WAF, ACL, Rate Limiting: GUI-controlled via Settings table
- CrowdSec: Environment variable controlled via docker-compose.yml
This created issues:
- ❌ Users had to restart containers to enable/disable CrowdSec
- ❌ GUI toggle didn't actually control the service
- ❌ Console enrollment could fail silently when LAPI wasn't running
- ❌ Inconsistent UX compared to other security features
The Solution: GUI-Based Control
Version 2.0 makes CrowdSec work like all other security features:
- ✅ Enable/disable via GUI toggle (no container restart)
- ✅ Real-time status visible in dashboard
- ✅ Better integration with Charon's security orchestration
- ✅ Consistent UX across all security features
Migration Steps
Step 1: Check Current Configuration
Check if you have CrowdSec environment variables set:
grep -i "CROWDSEC_MODE" docker-compose.yml
If you see any of these:
CHARON_SECURITY_CROWDSEC_MODECERBERUS_SECURITY_CROWDSEC_MODECPM_SECURITY_CROWDSEC_MODE
...then you need to migrate.
Step 2: Remove Environment Variables
Edit your docker-compose.yml and remove these lines:
# REMOVE THESE LINES:
- CHARON_SECURITY_CROWDSEC_MODE=local
- CERBERUS_SECURITY_CROWDSEC_MODE=local
- CPM_SECURITY_CROWDSEC_MODE=local
Also remove (if present):
# These are no longer used (external mode removed)
- CERBERUS_SECURITY_CROWDSEC_API_URL=
- CERBERUS_SECURITY_CROWDSEC_API_KEY=
Example: Before
services:
charon:
image: ghcr.io/wikid82/charon:latest
environment:
- CHARON_ENV=production
- CHARON_SECURITY_CROWDSEC_MODE=local # ← Remove this
Example: After
services:
charon:
image: ghcr.io/wikid82/charon:latest
environment:
- CHARON_ENV=production
# CrowdSec is now GUI-controlled
Step 3: Restart Container
docker compose down
docker compose up -d
⚠️ Important: After restart, CrowdSec will NOT be running by default. You must enable it via the GUI (next step).
Step 4: Enable CrowdSec via GUI
- Open Charon UI (default:
http://localhost:8080) - Navigate to Security in the sidebar
- Find the CrowdSec card
- Toggle the switch to ON
- Wait 10-15 seconds for LAPI to start
- Verify status shows "Active" with a running PID
Step 5: Verify LAPI is Running
docker exec charon cscli lapi status
Expected output:
✓ You can successfully interact with Local API (LAPI)
If you see this, migration is complete! ✅
Database Migrations for Upgrades
What Are Database Migrations?
Charon version 2.0 introduced new database tables to support security features like CrowdSec, WAF configurations, and security audit logs. If you're upgrading from version 1.x with persistent data, you need to run migrations to add these tables.
Do I Need to Run Migrations?
Yes, if:
- ✅ You're upgrading from Charon 1.x to 2.x
- ✅ You're using a persistent volume for
/app/data - ✅ You see "CrowdSec not starting" after upgrade
- ✅ Container logs show:
WARN security tables missing
No, if:
- ❌ This is a fresh installation (tables created automatically)
- ❌ You're not using persistent storage
- ❌ You've already run migrations once
How to Run Migrations
Step 1: Execute Migration Command
docker exec charon /app/charon migrate
Expected Output:
{"level":"info","msg":"Running database migrations for security tables...","time":"2025-12-15T..."}
{"level":"info","msg":"Migration completed successfully","time":"2025-12-15T..."}
Step 2: Verify Tables Created
docker exec charon sqlite3 /app/data/charon.db ".tables"
You should see these tables:
security_configs— Security feature settings (replaces environment variables)security_decisions— CrowdSec blocking decisionssecurity_audits— Security event audit logsecurity_rule_sets— WAF and rate limiting rulescrowdsec_preset_events— CrowdSec Hub preset trackingcrowdsec_console_enrollments— CrowdSec Console enrollment state
Step 3: Restart Container
If you had CrowdSec enabled before the upgrade, restart to apply changes:
docker restart charon
CrowdSec will automatically start if it was previously enabled.
Step 4: Verify CrowdSec Status
Wait 15 seconds after restart, then check:
docker exec charon cscli lapi status
Expected Output (if CrowdSec was enabled):
✓ You can successfully interact with Local API (LAPI)
What Gets Migrated?
The migration creates empty tables with the correct schema. Your existing data (proxy hosts, certificates, users, etc.) is not modified.
New tables added:
- SecurityConfig: Stores security feature state (on/off)
- SecurityDecision: Tracks CrowdSec blocking decisions
- SecurityAudit: Logs security-related actions
- SecurityRuleSet: Stores WAF rules and rate limits
- CrowdsecPresetEvent: Tracks Hub preset installations
- CrowdsecConsoleEnrollment: Stores Console enrollment tokens
Migration is Safe
✅ Idempotent: Safe to run multiple times (no duplicates) ✅ Non-destructive: Only adds tables, never deletes data ✅ Fast: Completes in <1 second ✅ No downtime: Container stays running during migration
Troubleshooting Migrations
"Migration command not found"
Cause: You're running an older version of Charon that doesn't include the migrate command.
Solution: Pull the latest image first:
docker compose pull
docker compose up -d
docker exec charon /app/charon migrate
"Database is locked"
Cause: Another process is accessing the database.
Solution: Retry in a few seconds:
sleep 5
docker exec charon /app/charon migrate
"Permission denied accessing database"
Cause: Database file has incorrect permissions.
Solution: Fix ownership (run on host):
sudo chown -R 1000:1000 ./charon-data
docker exec charon /app/charon migrate
"CrowdSec still not starting after migration"
See CrowdSec Troubleshooting for detailed diagnostics.
When Will This Be Automatic?
Future versions will detect missing tables on startup and run migrations automatically. For now, manual migration is required when upgrading from version 1.x.
Console Enrollment (If Applicable)
If you were enrolled in CrowdSec Console before migration:
Your Enrollment is Preserved ✅
The enrollment data is stored in the database, not in environment variables. Your Console connection should still work after migration.
Verify Console Status
- Go to Cerberus → CrowdSec in the sidebar
- Check the Console enrollment status
- If it shows "Enrolled" → you're good! ✅
- If it shows "Not Enrolled" but you were enrolled before → see troubleshooting below
Re-Enroll (If Needed)
If enrollment was incomplete in v1.x (common issue), re-enroll now:
- Ensure CrowdSec is enabled via GUI toggle (see Step 4 above)
- Verify LAPI is running:
docker exec charon cscli lapi status - Go to Cerberus → CrowdSec
- Click Enroll with CrowdSec Console
- Paste your enrollment token from crowdsec.net
- Submit
⚠️ Note: Enrollment tokens are reusable — you can use the same token multiple times.
Benefits of GUI Control
Before (Environment Variables)
1. Edit docker-compose.yml
2. docker compose down
3. docker compose up -d
4. Wait for container to restart (30-60 seconds)
5. Hope CrowdSec started correctly
6. Check logs to verify
After (GUI Toggle)
1. Toggle switch in Security dashboard
2. Wait 10 seconds
3. See "Active" status immediately
Feature Comparison
| Aspect | Environment Variable (Old) | GUI Toggle (New) |
|---|---|---|
| Enable/Disable | Edit file + restart container | Click toggle |
| Time to apply | 30-60 seconds | 10-15 seconds |
| Status visibility | Check logs | Real-time dashboard |
| Downtime during change | ❌ Yes (container restart) | ✅ No (zero downtime) |
| Consistency with other features | ❌ Different from WAF/ACL | ✅ Same as WAF/ACL |
| Console enrollment requirement | ⚠️ Easy to forget LAPI check | ✅ UI warns if LAPI not running |
Troubleshooting
"CrowdSec won't start after toggling"
Solution:
-
Check container logs:
docker logs charon | grep crowdsec -
Verify config directory exists:
docker exec charon ls -la /app/data/crowdsec/config -
If missing, restart container:
docker compose restart -
Try toggling again in GUI
"Console enrollment still shows 'Not Enrolled'"
Solution:
-
Verify LAPI is running:
docker exec charon cscli lapi status -
If LAPI is not running:
- Toggle CrowdSec OFF in GUI
- Wait 5 seconds
- Toggle CrowdSec ON in GUI
- Wait 15 seconds
- Re-check LAPI status
-
Re-submit enrollment token (same token works)
"I want to keep using environment variables"
Not recommended. Environment variable control is deprecated and will be removed in a future version.
If you must:
The legacy environment variables still work in version 2.0 (for backward compatibility), but:
- ⚠️ They will be removed in version 3.0
- ⚠️ GUI toggle may not reflect actual state
- ⚠️ You'll encounter issues with Console enrollment
- ⚠️ You'll miss out on improved UX and features
Please migrate to GUI control.
"Can I automate CrowdSec control via API?"
Yes! Use the Charon API:
Enable CrowdSec:
curl -X POST http://localhost:8080/api/v1/admin/crowdsec/start
Disable CrowdSec:
curl -X POST http://localhost:8080/api/v1/admin/crowdsec/stop
Check status:
curl http://localhost:8080/api/v1/admin/crowdsec/status
See API Documentation for more details.
Rollback (Emergency)
If you encounter critical issues after migration, you can temporarily roll back to environment variable control:
-
Add back the environment variable:
environment: - CHARON_SECURITY_CROWDSEC_MODE=local -
Restart container:
docker compose down docker compose up -d -
Report the issue:
- GitHub Issues
- Describe what went wrong
- Attach relevant logs
⚠️ This is a temporary workaround. Please report issues so we can fix them.
Support
Need help?
- 📖 Full Documentation
- 🛡️ Security Features Guide
- 🐛 CrowdSec Troubleshooting
- 💬 Community Discussions
- 🐛 Report Issues
Summary
✅ Remove environment variables from docker-compose.yml ✅ Restart container ✅ Enable CrowdSec via GUI toggle in Security dashboard ✅ Verify LAPI is running ✅ Re-enroll in Console if needed (same token works)
Benefits:
- ⚡ Faster enable/disable (no container restart)
- 👀 Real-time status visibility
- 🎯 Consistent with other security features
- 🛡️ Better Console enrollment reliability
Timeline: Environment variable support will be removed in version 3.0 (estimated 6-12 months).