Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/traefik/traefik/llms.txt

Use this file to discover all available pages before exploring further.

Nomad Provider

A Story of Tags, Services & Nomads Attach tags to your Nomad services and let Traefik automatically discover and route traffic. The Nomad provider integrates with HashiCorp Nomad’s native service discovery for seamless routing in your Nomad cluster.

Quick Start

1

Enable Nomad Provider

providers:
  nomad:
    endpoint:
      address: "http://127.0.0.1:4646"
    exposedByDefault: true
    prefix: "traefik"
2

Add Tags to Nomad Job

job.nomad
job "web" {
  group "app" {
    service {
      name = "web"
      port = "http"
      
      tags = [
        "traefik.enable=true",
        "traefik.http.routers.web.rule=Host(`example.com`)",
        "traefik.http.routers.web.entrypoints=websecure",
      ]
    }
    
    task "server" {
      driver = "docker"
      
      config {
        image = "myapp:latest"
        ports = ["http"]
      }
    }
    
    network {
      port "http" {
        to = 8080
      }
    }
  }
}
3

Deploy Job

nomad job run job.nomad
Traefik automatically discovers the service!

How It Works

The Nomad provider:
  1. Queries Nomad API for registered services
  2. Watches for changes (optional) in real-time
  3. Extracts routing config from service tags
  4. Discovers allocation IPs and ports
  5. Creates routes dynamically
  6. Updates on events when allocations start/stop

Provider Configuration

endpoint

Nomad server connection settings.

address

Default: http://127.0.0.1:4646
providers:
  nomad:
    endpoint:
      address: "http://nomad.example.com:4646"

token

Optional, Default: "" Nomad ACL token:
providers:
  nomad:
    endpoint:
      token: "${NOMAD_TOKEN}"
Required ACL policy: read-job capability. See Nomad ACL documentation.

endpointWaitTime

Optional, Default: "" Watch block duration:
providers:
  nomad:
    endpoint:
      endpointWaitTime: "15s"

tls

TLS configuration:
providers:
  nomad:
    endpoint:
      address: "https://nomad.example.com:4646"
      tls:
        ca: "/path/to/ca.crt"
        cert: "/path/to/client.crt"
        key: "/path/to/client.key"
        insecureSkipVerify: false

prefix

Default: traefik Tag prefix for configuration:
providers:
  nomad:
    prefix: "lb"
Use tags like: lb.http.routers.app.rule=...

refreshInterval

Default: 15s Polling interval:
providers:
  nomad:
    refreshInterval: "30s"
Ignored when watch: true is enabled.

watch

Default: false Enable real-time event watching:
providers:
  nomad:
    watch: true

throttleDuration

Default: 0s Throttle event handling:
providers:
  nomad:
    watch: true
    throttleDuration: "2s"
Only works with watch: true.

exposedByDefault

Default: true
providers:
  nomad:
    exposedByDefault: false  # Require traefik.enable=true tag

stale

Default: false Allow stale reads for better performance:
providers:
  nomad:
    stale: true

defaultRule

Default: Host(`{{ normalize .Name }}`)
providers:
  nomad:
    defaultRule: "Host(`{{ .Name }}.nomad.example.com`)"

constraints

Optional, Default: "" Filter services by tags:
providers:
  nomad:
    constraints: "Tag(`production`)"

namespaces (Enterprise)

Optional, Default: "" Watch specific namespaces:
providers:
  nomad:
    namespaces:
      - "production"
      - "staging"
Requires Nomad Enterprise with namespace support.

allowEmptyServices

Default: false Create load balancers even with no healthy allocations:
providers:
  nomad:
    allowEmptyServices: true

Nomad Job Examples

Basic Web Service

job "webapp" {
  datacenters = ["dc1"]
  
  group "web" {
    count = 3
    
    network {
      port "http" {
        to = 8080
      }
    }
    
    service {
      name = "webapp"
      port = "http"
      
      tags = [
        "traefik.enable=true",
        "traefik.http.routers.webapp.rule=Host(`app.example.com`)",
        "traefik.http.routers.webapp.entrypoints=websecure",
        "traefik.http.routers.webapp.tls.certresolver=letsencrypt",
      ]
      
      check {
        type     = "http"
        path     = "/health"
        interval = "10s"
        timeout  = "2s"
      }
    }
    
    task "app" {
      driver = "docker"
      
      config {
        image = "myapp:v1.0"
        ports = ["http"]
      }
      
      resources {
        cpu    = 500
        memory = 256
      }
    }
  }
}

Service with Middleware

job "secure-api" {
  group "api" {
    service {
      name = "secure-api"
      port = "http"
      
      tags = [
        "traefik.enable=true",
        
        # Router
        "traefik.http.routers.api.rule=Host(`api.example.com`) && PathPrefix(`/v1`)",
        "traefik.http.routers.api.entrypoints=websecure",
        "traefik.http.routers.api.middlewares=auth,ratelimit,cors",
        
        # Middleware
        "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$...",
        "traefik.http.middlewares.ratelimit.ratelimit.average=100",
        "traefik.http.middlewares.ratelimit.ratelimit.burst=50",
        "traefik.http.middlewares.cors.headers.accesscontrolallowmethods=GET,POST,PUT",
        "traefik.http.middlewares.cors.headers.accesscontrolalloworigin=*",
        
        # Service
        "traefik.http.services.api.loadbalancer.healthcheck.path=/health",
        "traefik.http.services.api.loadbalancer.healthcheck.interval=10s",
      ]
    }
    
    # ... task definition
  }
}

Multi-Service Job

job "microservices" {
  group "app" {
    network {
      port "web" { to = 3000 }
      port "api" { to = 8080 }
    }
    
    # Frontend service
    service {
      name = "frontend"
      port = "web"
      
      tags = [
        "traefik.enable=true",
        "traefik.http.routers.frontend.rule=Host(`app.example.com`)",
      ]
    }
    
    # API service
    service {
      name = "api"
      port = "api"
      
      tags = [
        "traefik.enable=true",
        "traefik.http.routers.api.rule=Host(`api.example.com`)",
      ]
    }
    
    task "web" {
      driver = "docker"
      config {
        image = "frontend:latest"
        ports = ["web"]
      }
    }
    
    task "api" {
      driver = "docker"
      config {
        image = "api:latest"
        ports = ["api"]
      }
    }
  }
}

Canary Deployment

job "app" {
  group "stable" {
    count = 9
    
    service {
      name = "app"
      tags = [
        "traefik.enable=true",
        "traefik.http.routers.app.rule=Host(`app.example.com`)",
        "traefik.http.services.app.loadbalancer.weight=90",
      ]
    }
    
    task "app" {
      driver = "docker"
      config {
        image = "app:v1.0"
      }
    }
  }
  
  group "canary" {
    count = 1
    
    service {
      name = "app-canary"
      tags = [
        "traefik.enable=true",
        "traefik.http.routers.app.rule=Host(`app.example.com`)",
        "traefik.http.services.app-canary.loadbalancer.weight=10",
      ]
    }
    
    task "app" {
      driver = "docker"
      config {
        image = "app:v2.0-beta"
      }
    }
  }
}

Complete Traefik Deployment

job "traefik" {
  datacenters = ["dc1"]
  type        = "system"  # Run on all nodes
  
  group "traefik" {
    network {
      port "http" {
        static = 80
      }
      port "https" {
        static = 443
      }
      port "admin" {
        static = 8080
      }
    }
    
    service {
      name = "traefik"
      port = "http"
      
      tags = [
        "traefik.enable=true",
        "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`)",
        "traefik.http.routers.dashboard.service=api@internal",
      ]
    }
    
    task "traefik" {
      driver = "docker"
      
      config {
        image = "traefik:v3.6"
        network_mode = "host"
        
        volumes = [
          "local/traefik.yml:/etc/traefik/traefik.yml",
        ]
      }
      
      template {
        data = <<EOF
entryPoints:
  web:
    address: ":80"
  websecure:
    address: ":443"

providers:
  nomad:
    endpoint:
      address: "http://{{ env "NOMAD_IP_admin" }}:4646"
    watch: true
    exposedByDefault: false

api:
  dashboard: true
EOF
        destination = "local/traefik.yml"
      }
      
      resources {
        cpu    = 500
        memory = 512
      }
    }
  }
}

Network Modes

Bridge Mode (Default)

network {
  mode = "bridge"
  port "http" {
    to = 8080
  }
}
Traefik connects to allocation’s private IP.

Host Mode

network {
  mode = "host"
  port "http" {
    static = 8080
  }
}
Direct node IP access.

CNI Plugins

network {
  mode = "bridge"
  port "http" {}
}
With Consul Connect or other CNI plugins.

Tag Syntax

All Traefik labels work as Nomad tags:
traefik.http.routers.app.rule=Host(`example.com`)
traefik.http.routers.app.middlewares=auth

Troubleshooting

Services Not Discovered

1

Check Nomad Connection

curl http://127.0.0.1:4646/v1/services
2

Verify Service Registration

nomad service list
nomad service info webapp
3

Check ACL Token

nomad acl token self
Ensure read-job policy is attached.
4

Review Traefik Logs

nomad alloc logs -f <traefik-alloc-id>

Health Check Issues

Ensure service has health checks:
service {
  check {
    type     = "http"
    path     = "/health"
    interval = "10s"
    timeout  = "2s"
  }
}

ACL Configuration

Create policy for Traefik:
# traefik-policy.hcl
namespace "*" {
  policy = "read"
  capabilities = ["read-job"]
}
Apply policy:
nomad acl policy apply traefik-policy traefik-policy.hcl
nomad acl token create -name="traefik" -policy=traefik-policy

Best Practices

1

Enable Watch Mode

Use watch: true for real-time updates instead of polling.
2

Use Health Checks

Always configure Nomad service health checks.
3

Tag Consistently

Develop a tagging strategy (environment, version, team).
4

Secure ACL Tokens

Use minimum required permissions and rotate tokens regularly.
5

Set Stale Reads

Enable stale: true for better performance in large clusters.

Next Steps

Nomad Routing

Detailed tag configuration reference

Nomad Documentation

Official HashiCorp Nomad documentation