Skip to content

Security

Traefik Manager is designed to run behind a reverse proxy on a trusted network. This page covers the security controls built in and how to harden your installation.

Looking to harden Traefik itself (underscore header spoofing, encoded characters, forwardAuth limits, CVE advisories)? See Traefik Security Hardening.


Authentication

Password

The login password is hashed with bcrypt at cost 12 before storage in manager.yml. The plaintext password is never written to disk.

Login POSTs are rate-limited to 5 per minute per IP, successful or not.

While ADMIN_PASSWORD is set, login compares that plaintext value instead of the stored hash, and 2FA, the in-UI password change and flask reset-password all have no effect.

Session management

Sessions use signed client-side cookies (Flask SecureCookieSession). The signing key is generated once and persisted to /app/config/.secret_key - it does not change on restart, so sessions survive container restarts.

SettingValue
Max session lifetime7 days (when "Remember me" is checked)
Inactivity timeout120 minutes, configurable via INACTIVITY_TIMEOUT_MINUTES; 24x that value for "Remember me" sessions - 48 hours at the default
Cookie flagsHttpOnly, SameSite=Lax (always on)
Secure flagOff by default - set COOKIE_SECURE=true env var

Set COOKIE_SECURE=true whenever TM is accessed over HTTPS. Without it, browsers may send cookies over HTTP, which is a risk if your reverse proxy is not enforcing HTTPS-only access. It also adds a Strict-Transport-Security response header.

Logging out clears the session.


Authentication modes

Traefik Manager has two independent web-UI auth mechanisms - built-in password and OIDC / SSO - plus API keys for programmatic access. Access to the UI is required whenever either password or OIDC is enabled:

PasswordOIDCResult
EnabledOffPassword login (optionally with 2FA).
EnabledEnabledLogin page offers both.
DisabledEnabledOIDC is the sole login - the password form is hidden and users are sent to your identity provider.
DisabledOffNo authentication - the UI is publicly accessible. A red warning is shown in the app and Settings, and logged at startup. Avoid this outside a fully trusted, isolated network, or acknowledge it if a reverse proxy already requires a login.

Disabling built-in authentication only turns off the password form - it does not disable OIDC. API keys keep working in every mode, so the mobile app and automation are unaffected when OIDC is your only interactive login.

Authentication handled by a reverse proxy

If something in front of Traefik Manager already requires a login - Authelia, Authentik, GateKeeper, or any forward-auth middleware - then running with both mechanisms off is a deliberate choice, and the red warning is noise. Under Settings → Authentication, the warning offers Acknowledge and hide. It is stored in manager.yml as auth_external_ack, so it applies to every browser and survives restarts, and the startup log drops from a SECURITY: warning to an informational line.

This changes what you are told, never what is enforced. Traefik Manager still authenticates nobody, so anything that reaches it directly - another container on the same Docker network, a LAN client hitting the port, a route that bypasses your middleware - has full administrative access. The acknowledgement cannot be set while a password or OIDC is active, and Settings keeps showing a neutral note stating that authentication is delegated, with an Undo link.

Recovery / lockout safety: disabling built-in authentication preserves your password hash in manager.yml. If your OIDC provider becomes unreachable and you are locked out, set auth_enabled: true in manager.yml and restart the container - the password form returns and you can log in with your existing password. You can also generate a fresh password with flask reset-password (see the Reset Password guide).

OIDC / SSO login

TM supports OpenID Connect, either alongside the built-in password or as the sole login method (disable built-in authentication to make OIDC mandatory). When enabled, a "Sign in with [provider]" button appears on the login page.

Supported providers include Google, Keycloak, Authentik, Entra ID, Zitadel, and any OIDC-compliant identity provider. Access can be restricted to specific email addresses or groups.

See the OIDC setup guide for full configuration details.

SettingDetail
Client secret storageFernet-encrypted at rest (same key as TOTP secret)
CSRF protectionstate parameter validated on callback
Rate limit on /auth/oidc/login10 / min per IP
Token exchangeServer-side only - no tokens exposed to the browser

Two-factor authentication (TOTP)

TM supports TOTP-based 2FA compatible with any standard authenticator app (Google Authenticator, Authy, etc.).

The TOTP secret is encrypted at rest using Fernet symmetric encryption. The encryption key is independent of the session signing key: it is taken from the OTP_ENCRYPTION_KEY environment variable, or generated once and persisted to /app/config/.otp_key. The same key encrypts every other stored secret - OIDC client secret, Traefik API password, CrowdSec keys, webhook password, git backup token. Only the encrypted values are stored in manager.yml.

2FA can be reset via the reset password page if you lose access to your authenticator.


API keys

API keys are used by the mobile app and scripts to access the API without a browser session.

  • Up to 10 keys can exist simultaneously, each with a device name for identification
  • Each key is hashed with SHA-256 - the plaintext is shown once at creation and never stored
  • Keys are revoked by their preview (first 8 and last 4 characters), not by device name. Revoking one device does not affect others
  • Generation is rate-limited to 5 per hour per IP

Keys are passed via the X-Api-Key request header:

X-Api-Key: your-key-here

CSRF protection

All state-changing requests (POST, PUT, PATCH, DELETE) require a CSRF token when using session authentication. The token is embedded in every HTML page and is generated once per session.

API key requests are exempt from CSRF checks only when a valid key is provided. A request with a missing or invalid key still requires a CSRF token.


External auth providers

When an external provider such as Authentik, Authelia, or Keycloak already protects TM through Traefik's forwardAuth middleware, you can turn the built-in auth off and acknowledge the no-authentication warning so it stops being reported as a misconfiguration.

Mobile app compatibility

forwardAuth intercepts all requests including mobile app API calls. To use the mobile app alongside an external auth provider, split the Traefik route so /api/* bypasses forwardAuth and relies on Traefik Manager's built-in API key auth. See the mobile app docs for the full example.


Rate limiting

EndpointLimit
Login, OTP verification5 / min per IP
OIDC login initiation10 / min per IP
Password change10 / min per IP
Backup restore10 / min per IP
Setup connection tests (CrowdSec, git)10 / min per IP
API key generation5 / hour per IP
GeoIP database update6 / hour per IP
All other endpointsUnlimited

Counters live in memory, per gunicorn worker, so they reset on restart.


Browser autofill

Every field in the app except the sign-in form is marked so browsers and password managers do not autofill it. Credential fields inside the app (API user and password, git backup token, CrowdSec key, the basic-auth and digest-auth generators) are marked new-password, which stops Chrome offering saved logins and prompting to save what you type there.

The sign-in form is deliberately untouched, so your password manager still works where it should. The password change and TOTP fields in Settings keep their proper current-password, new-password, and one-time-code semantics.


Outbound requests (SSRF protection)

Several features make TM issue outbound HTTP requests on your behalf - the Traefik connection tests, the CrowdSec and git setup tests, the webhook test, the URL ping tool, and the OIDC provider test. To prevent these from being used to reach cloud metadata endpoints, these fetchers reject:

  • Link-local addresses (169.254.0.0/16, including the 169.254.169.254 cloud metadata IP)
  • Multicast, reserved, and unspecified addresses

Private and loopback targets are still allowed, because reaching internal services (e.g. http://traefik:8080) is the normal, legitimate use for a self-hosted reverse-proxy manager. Redirects are not followed on the ping tool.


IP geolocation

IP geolocation (off by default) resolves client IPs to countries entirely on the server against a local database - IP addresses are never sent to any third-party geolocation API. The only outbound request downloads the database file itself from download.db-ip.com, and only when the feature is enabled: at startup TM re-downloads it if the local file is older than 35 days. Point GEOIP_DB_PATH at your own .mmdb to control which database is used, and keep its mtime fresh (or leave the feature disabled) to stay fully offline.


Git backup safety

When you configure git backup:

  • The repository URL must use https://, http://, ssh://, or git://. Other transports (ext::, file://, fd::) are rejected, and git is invoked with protocol.ext.allow=never, so a crafted URL cannot execute local commands.
  • The access token is passed to git through GIT_ASKPASS rather than being embedded in the remote URL. It is not written to .git/config, does not appear in process arguments, and is redacted from any error message shown in the UI.

Run behind a reverse proxy with HTTPS

Never expose Traefik Manager directly on port 5000 to the internet. Use a reverse proxy (Traefik itself works well) with a valid TLS certificate.

  1. Use HTTPS - configure a cert resolver in Traefik and enable the self-route in TM Settings
  2. Set COOKIE_SECURE=true in your docker-compose environment
  3. Enable 2FA via Settings → Authentication → Password & 2FA
  4. Use per-device API keys - generate a separate key for each device/script, revoke individually if compromised
  5. Mount config files read-only where possible - TM needs write access to CONFIG_DIR, /app/config, and BACKUP_DIR (default /app/backups)

Static config editor

The Static Config editor lets you edit traefik.yml directly from the UI and restart Traefik with one click. This has security implications beyond the dynamic config:

  • Read-write mount - traefik.yml must be mounted without :ro, giving TM write access to Traefik's entire static configuration including entrypoints, providers, and TLS settings
  • Restart access - RESTART_METHOD selects how Traefik is restarted, and each option has a different trust boundary:
MethodAccess granted
proxy (default, recommended)TM connects to a socket proxy sidecar limited to container restart operations only
poison-pillTM writes a signal file to a shared volume - no Docker API access at all
socketTM has direct access to the Docker socket - broadest access

The socket proxy and poison-pill methods limit the blast radius if TM is compromised. Direct socket access allows TM to interact with any container on the host.

If you do not use the Static Config editor, do not mount traefik.yml read-write and do not set RESTART_METHOD.


File permissions

TM writes to these locations (default paths - they follow SETTINGS_PATH):

PathPurpose
/app/config/manager.ymlSettings, hashed password, API key hashes, encrypted secrets
/app/config/.secret_keySession signing key (generated once, written 0600)
/app/config/.otp_keyFernet key for the TOTP secret and every other stored secret
CONFIG_DIR / CONFIG_PATHSDynamic Traefik config files

/app/config/ is the most sensitive directory: it holds the password hash and both encryption keys. Own it as the container user and keep it out of world-readable host directories - .secret_key is created 0600, but .otp_key is written with the process umask.

If you provide your own session key with the SECRET_KEY environment variable, it must be at least 32 characters - TM refuses to start with a shorter key.