A Traefik middleware plugin that implements a queue management system for your services, helping to manage traffic spikes by limiting the number of concurrent users and providing a fair waiting experience.
See the forums for further discussion here Make Traefik a powerful static file server!
When traffic exceeds your configured capacity:
- New visitors are placed in a queue
- Users are shown their position in the queue with estimated wait time
- The queue page automatically refreshes at configurable intervals
- When capacity becomes available, visitors are let in based on first-come, first-served
The plugin uses a client identifier (cookie or IP+UserAgent hash) to track visitors and ensure a fair queuing system.
- Configurable maximum number of concurrent users
- Custom queue page template
- Adjustable expiration time for sessions
- Option to use cookies or IP+UserAgent hash for visitor tracking
- Real-time capacity monitoring
- Visual progress indication for waiting users
# Static configuration
experimental:
plugins:
traefik-queue-manager:
moduleName: "github.com/hhftechnology/traefik-queue-manager"
version: "v1.0.0"
-
Clone the repository:
git clone https://github.com/hhftechnology/traefik-queue-manager.git
-
Build and install the plugin:
cd traefik-queue-manager go build -o traefik-queue-manager
-
Configure Traefik to use the local plugin:
# Static configuration experimental: localPlugins: traefik-queue-manager: moduleName: "github.com/hhftechnology/traefik-queue-manager"
Option | Type | Default | Description |
---|---|---|---|
enabled |
boolean | true |
Enable/disable the queue manager |
queuePageFile |
string | queue-page.html |
Path to the queue page HTML template |
sessionTime |
duration | 60 |
Duration for which a visitor session is valid |
purgeTime |
duration | 300 |
How often expired sessions are purged from cache |
maxEntries |
int | 100 |
Maximum number of concurrent users allowed |
httpResponseCode |
int | 429 |
HTTP response code for queue page |
httpContentType |
string | text/html; charset=utf-8 |
Content type of queue page |
useCookies |
boolean | true |
Use cookies for tracking; if false, uses IP+UserAgent hash |
cookieName |
string | queue-manager-id |
Name of the cookie used for tracking |
cookieMaxAge |
int | 3600 |
Max age of the cookie in seconds |
refreshInterval |
int | 30 |
Refresh interval in seconds |
debug |
boolean | false |
Enable debug logging |
# Dynamic configuration with Docker provider
labels:
- traefik.http.middlewares.queuemanager.plugin.queuemanager.enabled=true
- traefik.http.middlewares.queuemanager.plugin.queuemanager.queuePageFile=/path/to/queue-page.html
- traefik.http.middlewares.queuemanager.plugin.queuemanager.maxEntries=500
- traefik.http.middlewares.queuemanager.plugin.queuemanager.sessionTime=5m
- traefik.http.middlewares.queuemanager.plugin.queuemanager.useCookies=true
- traefik.http.middlewares.queuemanager.plugin.queuemanager.cookieName=queue-manager-id
You can customize the queue page by modifying the HTML template. The template supports the following variables:
[[.Position]]
- Current position in queue[[.QueueSize]]
- Total queue size[[.EstimatedWaitTime]]
- Estimated wait time in minutes[[.RefreshInterval]]
- Refresh interval in seconds[[.ProgressPercentage]]
- Visual progress percentage[[.Message]]
- Custom message
services:
traefik:
image: traefik:v3.3.4
container_name: traefik
command:
- --log.level=INFO
- --api.insecure=true
- --providers.docker=true
- --entrypoints.web.address=:80
- --experimental.localPlugins.queuemanager.moduleName=github.com/hhftechnology/traefik-queue-manager
ports:
- "80:80"
- "8080:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./:/plugins-local/src/github.com/hhftechnology/traefik-queue-manager
labels:
- traefik.http.middlewares.queuemanager.plugin.queuemanager.enabled=true
- traefik.http.middlewares.queuemanager.plugin.queuemanager.queuePageFile=/plugins-local/src/github.com/hhftechnology/traefik-queue-manager/queue-page.html
- traefik.http.middlewares.queuemanager.plugin.queuemanager.maxEntries=5
- traefik.http.middlewares.queuemanager.plugin.queuemanager.sessionTime=1m
myservice:
image: traefik/whoami
container_name: myservice
labels:
- traefik.enable=true
- traefik.http.routers.myservice.rule=Host(`service.local`)
- traefik.http.routers.myservice.entrypoints=web
- traefik.http.routers.myservice.middlewares=queuemanager
# This is an example of how to configure the Queue Manager middleware
# in your Traefik dynamic configuration.
#
# If using Docker labels, you would prefix these with:
# "traefik.http.middlewares.my-queue-middleware.plugin.queuemanager."
#
# Example for a middleware named "my-queue-middleware":
#
# http:
# middlewares:
# my-queue-middleware:
# plugin:
# queuemanager:
# # --- Basic Settings ---
# enabled: true
# # Description: Globally enables or disables the queue manager middleware.
# # Default: true
# # Tuning: Set to `false` to bypass queueing entirely without removing the middleware configuration.
#
# maxEntries: 50
# # Description: The maximum number of concurrent users allowed to access the target service
# # before new users are placed into the queue.
# # Default: 100 (from CreateConfig in Go code)
# # Tuning: This is the most critical value. Set it based on your backend service's actual capacity
# # to handle concurrent requests without performance degradation. Start conservatively and monitor.
#
# # --- Session Timeouts ---
# inactivityTimeoutSeconds: 300
# # Description: Defines how long an *active* user's session remains valid if they are inactive
# # (i.e., make no further requests to the service). After this period, their slot may be freed up.
# # Default: 60 (from CreateConfig in Go code)
# # Tuning:
# # - Too short: Users reading a page or briefly idle might get requeued.
# # - Too long: Idle users occupy slots longer, slowing queue progression.
# # - Consider average user interaction time. 5-10 minutes (300-600s) is often reasonable.
#
# hardSessionLimitSeconds: 3600
# # Description: (Optional) An absolute maximum duration (in seconds) for any active session,
# # regardless of user activity. If set to 0, this feature is disabled.
# # Default: 0 (disabled, from CreateConfig in Go code)
# # Tuning: Use this to ensure fair access over very long periods or to prevent indefinitely held slots.
# # For example, 3600 (1 hour) ensures a slot is freed at least hourly.
#
# # --- Queue Mechanics ---
# cleanupIntervalSeconds: 60
# # Description: How frequently the plugin's internal cleanup process runs. This process evicts
# # expired (inactive or hard-limited) sessions and promotes users from the queue.
# # Default: 30 (from CreateConfig in Go code, previously 300 in older versions)
# # Tuning: Should be responsive. A good value is often `inactivityTimeoutSeconds / 2` or at least
# # no more than `inactivityTimeoutSeconds`. A value like 30-60 seconds ensures timely promotions.
#
# queueStrategy: "fifo"
# # Description: The strategy for processing the queue. Currently, only "fifo" (First-In, First-Out)
# # is implemented and supported.
# # Default: "fifo" (from CreateConfig in Go code)
# # Tuning: Stick with "fifo" for fairness.
#
# # --- Queue Page Customization ---
# queuePageFile: "/etc/traefik/queue-templates/my-custom-queue-page.html"
# # Description: Absolute path to your custom HTML template file for the queue page.
# # The plugin needs read access to this file from where Traefik is running (e.g., inside the Traefik container).
# # If not provided or the file is not found, a built-in default template is used.
# # Default: "queue-page.html" (relative path, from CreateConfig in Go code, ensure it's accessible)
# # Tuning: Customize this page for branding and user experience. Ensure it uses the placeholders
# # like `[[.RefreshInterval]]`, `[[.Position]]`, `[[.QueueSize]]`, etc.
#
# refreshIntervalSeconds: 20
# # Description: How often the queue page (served to waiting users) automatically refreshes
# # to update their position and estimated wait time. This value is passed to the `[[.RefreshInterval]]`
# # placeholder in your `queuePageFile`.
# # Default: 20 (from CreateConfig in Go code, previously 30 in older versions)
# # Tuning: 15-30 seconds is a good range. Too short can be distracting; too long makes users feel uninformed.
#
# minWaitTimeMinutes: 1
# # Description: The minimum estimated wait time (in minutes) that will be displayed to users,
# # even if the calculated wait time is less (but not zero). Prevents showing "0 minutes" if they are still queued.
# # Default: 1 (from CreateConfig in Go code)
# # Tuning: 1-2 minutes is usually a good minimum to manage expectations.
#
# httpResponseCode: 429
# # Description: The HTTP status code returned when serving the queue page.
# # `429 Too Many Requests` is semantically appropriate.
# # Default: 429 (from CreateConfig in Go code)
# # Tuning: Usually no need to change. `503 Service Unavailable` is an alternative.
#
# httpContentType: "text/html; charset=utf-8"
# # Description: The Content-Type header for the queue page.
# # Default: "text/html; charset=utf-8" (from CreateConfig in Go code)
# # Tuning: Keep as is for standard HTML pages.
#
# # --- Client Identification (Cookies) ---
# useCookies: true
# # Description: Whether to use cookies (`true`) or an IP Address + User-Agent hash (`false`)
# # to identify and track users.
# # Default: true (from CreateConfig in Go code)
# # Tuning: `true` (cookies) is generally recommended for better accuracy and fairness, especially
# # if users might share IPs or have dynamic IPs.
#
# cookieName: "my_app_queue_id"
# # Description: The name of the cookie used for tracking if `useCookies` is `true`.
# # Default: "queue-manager-id" (from CreateConfig in Go code)
# # Tuning: Change if the default name conflicts with other cookies used by your applications.
#
# cookieMaxAgeSeconds: 7200
# # Description: The maximum age of the tracking cookie in the user's browser (in seconds).
# # This determines how long a user might be remembered if they close and reopen their browser.
# # It's different from server-side session timeouts.
# # Default: 3600 (1 hour, from CreateConfig in Go code)
# # Tuning: 1-2 hours (3600-7200s) is common. Longer might be convenient for users in very long queues.
#
# # --- Logging & Debugging ---
# debug: false
# # Description: Enables verbose debug logging for the plugin. This will override `logLevel` to "debug".
# # Default: false (from CreateConfig in Go code)
# # Tuning: Set to `true` ONLY for troubleshooting. Disable in production as it's very verbose.
#
# logLevel: "info"
# # Description: Sets the logging level for the plugin. Options: "debug", "info", "warn", "error".
# # If `debug` is `true`, this is effectively "debug".
# # Default: "info" (from CreateConfig in Go code)
# # Tuning: "info" is good for production. "warn" or "error" for less verbosity if "info" is too much.
#
# logFile: ""
# # Description: (Optional) Path to a file where plugin logs should be written.
# # If empty or not specified, logs go to Traefik's standard output (stderr).
# # Ensure Traefik has write permissions to this path if specified.
# # Default: "" (stderr, from CreateConfig in Go code)
# # Tuning: Use if you want to separate queue manager logs from main Traefik logs.
#
# Example of applying this middleware to a router (e.g., in Docker labels):
# labels:
# - "traefik.http.routers.my-service.middlewares=my-queue-middleware@file" # If defined in a file provider
# # or if defining the middleware directly on the router:
# - "traefik.http.routers.my-service.middlewares=my-queue"
# - "traefik.http.middlewares.my-queue.plugin.queuemanager.maxEntries=50"
# - "traefik.http.middlewares.my-queue.plugin.queuemanager.inactivityTimeoutSeconds=300"
# # ... and so on for other parameters ...
The plugin uses an in-memory cache to track active sessions, which provides excellent performance but means:
- If you're running multiple Traefik instances, each will maintain its own separate queue
- If Traefik restarts, all queue data is lost
For high-availability setups, consider using a shared Redis cache or similar solution.
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.