Local & Air-Gapped Deployment (/plugins-local)
This guide explains how to install, develop, and run RouteWarden in air-gapped, offline, and local enterprise environments using Traefik's native /plugins-local mechanism without external downloads from GitHub or the Traefik Plugin Catalog.
1. How Traefik Local Plugins Work
Traefik allows loading plugins directly from the host filesystem using the experimental.localPlugins configuration key. This provides several key advantages:
- 100% Offline / Air-Gapped: Traefik never calls out to
plugins.traefik.ioor GitHub, eliminating network timeouts, proxy issues, or firewall blocks. - Zero Build Steps: Traefik's embedded Yaegi Go interpreter compiles the
.gosource files directly in memory at launch. - Instant Live Iteration: Code changes take effect immediately on container restart without rebuilding container images or tagging releases.
When using localPlugins, Traefik strictly requires the source code to be mounted into a specific path matching Go's import hierarchy under /plugins-local/src/:
plugins-local/└── src/ └── github.com/ └── routewarden/ └── traefik-warden/ ├── .traefik.yml ├── config.go ├── ip_filter.go ├── path_normalizer.go ├── response_handler.go └── routewarden.go2. Local Traefik Configuration Preview
# traefik.yml (Static)experimental: localPlugins: routewarden: moduleName: github.com/routewarden/traefik-warden# dynamic_conf.yml (Dynamic Middleware & Router)http: middlewares: local-warden: plugin: routewarden: enabled: true enableDefaultPatterns: true response: mode: json statusCode: 403 body: '{"error":"Forbidden","environment":"local-dev"}' routers: app-router: rule: "Host(`localhost`)" entryPoints: - web middlewares: - local-warden service: app-service3. Local Docker Compose Setup
Here is a complete, ready-to-run docker-compose.yml for developing and testing RouteWarden locally:
services: traefik: image: traefik:latest command: - "--api.insecure=true" - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--entrypoints.web.address=:80" # Declare RouteWarden as a LOCAL plugin: - "--experimental.localPlugins.routewarden.modulename=github.com/routewarden/traefik-warden" # Log level debug helps verify plugin loading - "--log.level=DEBUG" ports: - "80:80" - "8080:8080" # Traefik Web UI & Middleware Explorer volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" # Mount your local repository directory into Traefik's plugins-local path: - ".:/plugins-local/src/github.com/routewarden/traefik-warden:ro" webapp: image: nginx:alpine labels: - "traefik.enable=true" - "traefik.http.routers.webapp.rule=Host(`localhost`)" - "traefik.http.routers.webapp.entrypoints=web" - "traefik.http.routers.webapp.middlewares=local-warden" # Middleware configuration - "traefik.http.middlewares.local-warden.plugin.routewarden.enabled=true" - "traefik.http.middlewares.local-warden.plugin.routewarden.enableDefaultPatterns=true" - "traefik.http.middlewares.local-warden.plugin.routewarden.response.mode=json" - "traefik.http.middlewares.local-warden.plugin.routewarden.response.statusCode=403" - 'traefik.http.middlewares.local-warden.plugin.routewarden.response.body={"error":"Forbidden","environment":"local-dev"}'4. Step-by-Step Local Walkthrough
Step 1: Start the Cluster
From the root of the RouteWarden repository:
docker compose upStep 2: Verify Plugin Initialization
Watch the Traefik startup logs. You should see Traefik's Yaegi interpreter successfully compiling the local plugin:
level=info msg="Loading plugin: routewarden with module: github.com/routewarden/traefik-warden"level=info msg="Plugin routewarden loaded successfully"Step 3: Inspect via Traefik Dashboard
Open your browser to: http://localhost:8080/dashboard/#/http/middlewares
You will see local-warden@docker listed with its active configuration.
Step 4: Test Blocking Live
curl -I http://localhost/# HTTP/1.1 200 OKStep 5: Live Code Iteration
Because the repository root is mounted with - .:/plugins-local/src/github.com/routewarden/traefik-warden:ro, whenever you modify Go code, simply restart Traefik to recompile:
docker compose restart traefik(No Docker rebuild or external plugin download required!)
5. Air-Gapped & Enterprise Production Setup
When deploying to production clusters with no public internet access (e.g., banking, healthcare, government, or private VPCs), follow these steps to bundle RouteWarden offline.
Step 1: Prepare the Offline Plugin Bundle
On an internet-connected workstation, clone the repository or download the release archive:
# Clone repository onto an internet-connected machinegit clone https://github.com/routewarden/traefik-warden.gitTransfer the traefik-warden/ directory to your air-gapped host (e.g., via secure artifact repository, internal registry, USB drive, or SCP).
Step 2: Production Docker Compose Setup
Place the traefik-warden directory adjacent to your docker-compose.yml:
# docker-compose.yml (Air-Gapped Production via /plugins-local)services: traefik: image: traefik:latest command: - "--providers.docker=true" - "--providers.file.filename=/etc/traefik/dynamic.yml" - "--entrypoints.web.address=:80" - "--entrypoints.websecure.address=:443" # Enable offline local plugin: - "--experimental.localplugins.routewarden.modulename=github.com/routewarden/traefik-warden" # Attach globally to entrypoints: - "--entrypoints.web.http.middlewares=routewarden@file" - "--entrypoints.websecure.http.middlewares=routewarden@file" ports: - "80:80" - "443:443" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./dynamic.yml:/etc/traefik/dynamic.yml:ro # Mount RouteWarden into required /plugins-local destination: - ./traefik-warden:/plugins-local/src/github.com/routewarden/traefik-warden:roStep 3: Kubernetes Air-Gapped Deployment
In Kubernetes environments using the official Traefik Helm chart or direct manifests, mount the plugin source:
# Helm values.yaml for TraefikadditionalArguments: - "--experimental.localplugins.routewarden.modulename=github.com/routewarden/traefik-warden"extraVolumes: - name: routewarden-plugin configMap: name: routewarden-plugin-sourceextraVolumeMounts: - name: routewarden-plugin mountPath: /plugins-local/src/github.com/routewarden/traefik-warden readOnly: true6. Common Pitfalls & Troubleshooting
| Symptom | Cause | Solution |
|---|---|---|
unable to find plugin "routewarden" | Incorrect container mount path | Ensure the destination path inside the container is exactly /plugins-local/src/github.com/routewarden/traefik-warden, NOT /plugins-local/traefik-warden. |
permission denied | File permission restrictions | Ensure the Traefik process has read access (chmod -R 755 traefik-warden). |
missing plugin manifest | Missing .traefik.yml file | Verify that .traefik.yml is present in the root of the mounted directory. |
module name mismatch | CLI flag does not match directory | Verify --experimental.localplugins.routewarden.modulename=github.com/routewarden/traefik-warden exactly matches the subpath /plugins-local/src/github.com/routewarden/traefik-warden. |