Skip to content

Support file and directory Traefik dynamic config paths#69

Open
smoochy wants to merge 2 commits intohhftechnology:pangolinfrom
smoochy:fix_TRAEFIK_DYNAMIC_CONFIG
Open

Support file and directory Traefik dynamic config paths#69
smoochy wants to merge 2 commits intohhftechnology:pangolinfrom
smoochy:fix_TRAEFIK_DYNAMIC_CONFIG

Conversation

@smoochy
Copy link
Copy Markdown
Contributor

@smoochy smoochy commented Mar 28, 2026

Summary

Allow TRAEFIK_DYNAMIC_CONFIG to point to either a single Traefik dynamic config file or a directory of dynamic config fragments.

Problem

Several code paths still assumed that the Traefik dynamic config was always a single file. The most visible breakage was in internal/api/handlers/captcha_setup.go, where the code built a hard-coded dynamic_config.yml path instead of using the configured target.

That fails for Traefik setups that load a directory such as /etc/traefik/rules, because CrowdSec Manager then tries to read or write the wrong target. It also risks writing to a shared base file when the correct behavior is to maintain a dedicated CrowdSec-managed overlay.

Solution

  • Added a central Traefik dynamic-config helper in internal/traefikconfig/traefik_dynamic_config.go to resolve file vs directory mode, map managed paths, and read combined fragment content.
  • Updated captcha writes in internal/api/handlers/captcha_setup.go and internal/api/handlers/captcha_config.go to write to the resolved managed file. In directory mode this is crowdsec-manager.yml.
  • Updated whitelist mutations in internal/api/handlers/whitelist.go and internal/api/handlers/whitelist_ops.go so CrowdSec Manager only writes to its managed overlay instead of touching shared files like base.yml.
  • Updated detection and diagnostics reads in internal/api/handlers/captcha_detect.go, internal/api/handlers/services.go, internal/api/handlers/health_diagnostics.go, and internal/api/handlers/services_config.go to support both a single file and a directory of YAML fragments.
  • Updated config validation in internal/configvalidator/validator.go to snapshot the resolved managed dynamic-config file instead of treating a directory as a plain file.
  • Added backend coverage in internal/traefikconfig/traefik_dynamic_config_test.go, internal/config/traefik_dynamic_config_test.go, and internal/api/handlers/captcha_setup_test.go.
  • Updated UI and docs so the setting is described as a config path, not only a single file path.

Testing

  • go test ./...

Misc

This PR also includes the fixes from #67

AI Transparency

This change was prepared with AI assistance.

@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 28, 2026

@smoochy is attempting to deploy a commit to the HHF Technologies' projects Team on Vercel.

A member of the Team first needs to authorize it.

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for directory-based Traefik dynamic configurations, allowing the TRAEFIK_DYNAMIC_CONFIG environment variable to point to either a single YAML file or a directory of configuration fragments. When a directory is used, CrowdSec Manager manages its own overlay file named crowdsec-manager.yml to avoid modifying user-defined files. The changes include a significant refactor of the backend handlers to use a new traefikconfig package for unified configuration access, updates to documentation and Docker Compose examples, and a fix in the web UI to normalize bouncer data shapes. Feedback is provided regarding the hardcoded path mapping in the configuration resolution logic, which may be brittle for custom volume mounts.

Comment on lines +160 to +173
func containerPathToHostPath(cfg *config.Config, containerPath string) (string, error) {
switch {
case containerPath == "/etc/traefik":
return filepath.Join(cfg.ConfigDir, "traefik"), nil
case strings.HasPrefix(containerPath, "/etc/traefik/"):
return filepath.Join(cfg.ConfigDir, "traefik", filepath.FromSlash(strings.TrimPrefix(containerPath, "/etc/traefik/"))), nil
case containerPath == "/rules":
return filepath.Join(cfg.ConfigDir, "traefik", "rules"), nil
case strings.HasPrefix(containerPath, "/rules/"):
return filepath.Join(cfg.ConfigDir, "traefik", "rules", filepath.FromSlash(strings.TrimPrefix(containerPath, "/rules/"))), nil
default:
return "", fmt.Errorf("unsupported Traefik container path: %s", containerPath)
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The containerPathToHostPath function relies on hardcoded path prefixes to map container paths to host paths. This assumes a specific volume mount structure as defined in the project's default docker-compose.yml files.

This implementation can be brittle. If a user customizes their volume mounts (e.g., mapping a different host directory to /etc/traefik in the container), this function will fail to find the correct host path, leading to errors when trying to read from or write to the host filesystem.

A more robust solution would be to dynamically determine the host path by inspecting the container's mount points using the Docker API. This would make the application more resilient to different user configurations.

@hhftechnology
Copy link
Copy Markdown
Owner

@smoochy this is a huge refactor. Can you dm me on discord for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants