Skip to main content

Amazon EC2

Early Access

This feature is currently in early access.

The ec2 provider enables Traefik Hub API Gateway to discover Amazon EC2 instances and automatically generate routing configuration from their tags. It follows the same label-based model as the Docker, ECS, and Consul Catalog providers: you apply traefik.* tags to your EC2 instances to define routers, services, middlewares, and load balancer settings, and the provider turns them into dynamic configuration.

This is useful for workloads running directly on EC2 instances, without a container orchestrator, that still need automatic service discovery and routing. As instances launch, terminate, or change addresses, the provider keeps the routing configuration in sync.

Overview

The provider polls the AWS EC2 API at a configurable interval to list running instances, filters them using user-defined EC2 filters and constraint expressions, and builds Traefik routing configuration from each instance's tags. HTTP, TCP, and UDP services are supported.

Key behaviors:

  • Tag-based configuration: Instances are configured through traefik.* tags, mirroring the Docker and Consul Catalog providers.
  • Running instances only: The provider always scopes discovery to instances in the running state. This is an AWS-side filter, not a health check; see Health checking.
  • Backend addressing: Backends target the instance's private IP by default, with public and IPv6 modes available. See ipMode.
  • Service merging: The service name is derived from each instance's Name tag. Instances sharing the same name are merged as servers behind the same load balancer.
  • Flexible credentials: Use static AWS credentials or the default AWS credential chain (IAM roles, environment variables, instance profiles). See Credentials.
  • Optional port discovery: When no port tag is set, the backend port can be derived from the instance's security-group rules. See securityGroupPortDiscovery.
  • Cross-provider reference: Reference discovered resources from other providers by suffixing the name with @ec2, e.g. a Kubernetes gateway routing to an EC2 backend. See Provider Namespace.

Configuration Example

To use the ec2 provider, you need to enable & configure it.

Below is an example of how to enable & configure the provider:

hub:
providers:
ec2:
enabled: true
region: "us-east-1"
exposedByDefault: false
refreshSeconds: 15
filters:
- name: "tag:env"
values:
- "production"
additionalArguments:
- "--hub.providers.ec2.region=us-east-1"
- "--hub.providers.ec2.exposedByDefault=false"
- "--hub.providers.ec2.refreshSeconds=15"
- "--hub.providers.ec2.filters[0].name=tag:env"
- "--hub.providers.ec2.filters[0].values=production"

Configuration Options

FieldDescriptionDefaultRequired
hub.providers.ec2.regionAWS region used for EC2 API requests. When empty, the region is retrieved from the EC2 Instance Metadata Service.""No
hub.providers.ec2.accessKeyIDAWS access key ID used for requests. When set together with secretAccessKey, these static credentials take priority over the default credential chain. See Credentials.""No
hub.providers.ec2.secretAccessKeyAWS secret access key used for requests. Must be set together with accessKeyID. See Credentials.""No
hub.providers.ec2.exposedByDefaultExpose discovered instances by default. When set to false, only instances with the traefik.enable=true tag are exposed. See exposedByDefault.trueNo
hub.providers.ec2.refreshSecondsPolling interval, in seconds, for the EC2 API.15No
hub.providers.ec2.defaultRuleDefault routing rule applied to instances that do not define a router rule tag. See defaultRule."Host(`{{ normalize .Name }}`)"No
hub.providers.ec2.constraintsExpression matched against instance tags to determine whether to create routes for an instance. See constraints.""No
hub.providers.ec2.ipModeDefault backend IP mode: private, public, or ipv6. Can be overridden per instance with the traefik.ec2.ipmode tag. See ipMode.privateNo
hub.providers.ec2.filtersList of EC2 API filters used to scope instance discovery. See filters.[]No
hub.providers.ec2.filters[n].nameEC2 filter name (for example tag:env, vpc-id, instance-type).""No
hub.providers.ec2.filters[n].valuesList of values for the filter.[]No
hub.providers.ec2.securityGroupPortDiscoveryEnable deriving the backend port from an instance's security-group rules when no port tag is set. See securityGroupPortDiscovery.N/ANo
hub.providers.ec2.securityGroupPortDiscovery.excludedPortsPorts excluded from security-group port discovery. When empty, the provider excludes port 0 and all privileged ports (below 1024) except 80 and 443.Privileged ports except 80 and 443No

region

The AWS region used for EC2 API requests. If region is not set, the provider retrieves the region from the EC2 Instance Metadata Service, which requires Traefik Hub to run on an EC2 instance.

Credentials

The provider authenticates against the AWS EC2 API in one of two ways:

  • Static credentials: When both accessKeyID and secretAccessKey are set, the provider uses only these credentials, and they take priority over any other source.
  • Default credential chain: When accessKeyID and secretAccessKey are not set, the provider falls back to the default AWS credential chain, which resolves credentials from environment variables, shared configuration files, IAM roles, and EC2 instance profiles.
tip

For workloads running on AWS, prefer an IAM role or instance profile over static credentials. The role needs permission to call ec2:DescribeInstances (and ec2:DescribeSecurityGroups when securityGroupPortDiscovery is enabled).

note

accessKeyID and secretAccessKey are sensitive values and are not logged.

exposedByDefault

When exposedByDefault is true (the default), every discovered instance is exposed unless it carries the traefik.enable=false tag. When set to false, instances are ignored unless they carry the traefik.enable=true tag.

defaultRule

The default routing rule applied to instances that do not define a router rule through a tag.

For a given instance, if no routing rule is defined by a tag, the defaultRule is used instead. The defaultRule must be a valid Go template, and can include sprig template functions. The instance name (derived from the Name tag) can be accessed with the Name identifier.

The default value is:

Host(`{{ normalize .Name }}`)

The rule can be overridden on an instance basis with the traefik.http.routers.{name-of-your-choice}.rule tag.

Discovering an instance without creating a route

Set defaultRule to an empty string to stop the provider from creating a route for instances that don't define their own router rule tag. This is useful when you only want an EC2 instance to be discoverable as a service — for example to reference it from another provider or cluster with the @ec2 suffix (see Provider Namespace) — without a route being created for it by default.

constraints

The constraints option can be set to an expression that Traefik Hub matches against an instance's tags to determine whether to create any route for that instance. If the tags do not match the expression, no route is created for that instance. If the expression is empty, all detected instances are included.

The expression syntax is based on the Label(`key`, `value`) and LabelRegex(`key`, `regex`) functions, as well as the usual boolean logic, as shown in the examples below.

Constraints Expression Examples
# Includes only instances having the tag `a.tag.name=foo`
constraints: "Label(`a.tag.name`, `foo`)"
# Excludes instances having the tag `a.tag.name=foo`
constraints: "!Label(`a.tag.name`, `foo`)"
# With logical AND.
constraints: "Label(`env`, `production`) && Label(`tier`, `web`)"
# With logical OR.
constraints: "Label(`env`, `production`) || Label(`env`, `staging`)"
# With logical AND and OR, with precedence set by parentheses.
constraints: "Label(`env`, `production`) && (Label(`tier`, `web`) || Label(`tier`, `api`))"
# Includes only instances whose `env` tag value matches the `prod-.+` regular expression.
constraints: "LabelRegex(`env`, `prod-.+`)"
# Includes only instances that carry the `env` tag at all, whatever its value.
# Use `.+` rather than `.*`: `.*` also matches instances that do not have the tag.
constraints: "LabelRegex(`env`, `.+`)"

filters

The filters option scopes instance discovery using the EC2 DescribeInstances filters. Each filter has a name and a list of values. Only instances matching every configured filter are considered.

File (YAML)
hub:
providers:
ec2:
filters:
- name: "vpc-id"
values:
- "vpc-0123456789abcdef0"
- name: "tag:env"
values:
- "production"
- "staging"
note

The provider always scopes discovery to running instances by injecting the instance-state-name=running filter. This filter is reserved: configuring a filter named instance-state-name causes the provider to fail at startup. Traefik continues to run without the EC2 provider and logs the reason at ERROR. This is a first-layer, AWS-side check only; it does not verify that the backend on the instance is actually healthy. See Health checking to add an application-level check on top of it.

Health checking

The running-state filter above only confirms that AWS considers the instance to be running — it is not an application-level health check. To validate that a backend is actually accepting traffic before routing to it, configure a health check through tags, for example:

traefik.http.services.{name-of-your-choice}.loadbalancer.healthcheck.path=/health
traefik.http.services.{name-of-your-choice}.loadbalancer.healthcheck.interval=10s

Health checking is optional and layered on top of the running-state filter: an instance can be in the running state and still be excluded from load balancing if its configured health check fails.

ipMode

The ipMode option selects which address of an instance the backends should target:

  • private (default): the instance's private IPv4 address.
  • public: the instance's public IPv4 address.
  • ipv6: the instance's IPv6 address.

The mode can be overridden on a per-instance basis with the traefik.ec2.ipmode tag. Instances without an address for the resolved mode are skipped.

warning

The private default only works when the Hub gateway itself runs inside the instance's VPC or a peered network. A gateway hosted outside AWS — or outside that VPC — cannot reach private addresses at all, so on that topology the default silently produces unroutable backends. Set ipMode to public (or override per instance with the traefik.ec2.ipmode tag) when the gateway doesn't run inside AWS.

securityGroupPortDiscovery

When no port is defined for an instance through a tag, the provider can derive the backend port from the instance's security-group rules. This is opt-in: set securityGroupPortDiscovery to enable it.

When enabled, the provider inspects the inbound rules of the security groups attached to the instance and uses the lowest FromPort for the relevant protocol (TCP or UDP), skipping any port listed in excludedPorts.

When excludedPorts is not set, the provider skips port 0 and all privileged ports (below 1024) except 80 and 443. Ports at or above 1024 are eligible, so an instance whose security group exposes an application or database port will be routed to it unless you exclude that port explicitly.

Setting excludedPorts replaces this rule rather than adding to it: only the ports you list are skipped, and the privileged-port range no longer applies.

File (YAML)
hub:
providers:
ec2:
securityGroupPortDiscovery:
excludedPorts:
- 8080
excludedPorts overrides, not extends, the default

The example above excludes only port 8080. Setting excludedPorts replaces the default privileged-port range entirely rather than adding to it, so every other privileged port — including 22, 25, and 3389 — becomes eligible for port discovery once excludedPorts is set.

note

Security-group port discovery only applies when an instance does not set an explicit port tag. When enabled, the provider also needs the ec2:DescribeSecurityGroups permission.

Routing Configuration with Tags

The provider reads traefik.* tags from each EC2 instance and decodes them into routers, services, and middlewares, exactly like the label-based providers. Provider-specific options use the traefik.ec2. prefix. Few examples:

TagDescription
traefik.enableWhether to expose the instance. Interacts with exposedByDefault.
traefik.ec2.ipmodeOverrides the provider-level ipMode for this instance (private, public, or ipv6).
traefik.http.routers.<name>.ruleDefines the routing rule for an HTTP router, overriding the defaultRule.
traefik.http.services.<name>.loadbalancer.server.portSets the backend port for an HTTP service.
traefik.tcp.routers.<name>.ruleDefines the routing rule for a TCP router.
traefik.udp.routers.<name>.entrypointsAssigns entry points for a UDP router.

The full set of routing tags follows the same naming as the standard Traefik label-based providers. See the Docker provider labels documentation for the complete label/tag syntax reference — for example, traefik.http.middlewares.<name>.<middleware-type>.<option> to configure middlewares, or traefik.http.services.<name>.loadbalancer.server.scheme to set the backend scheme.

traefik.enable=true
traefik.http.routers.my-app.rule=Host(`my-app.example.com`)
traefik.http.services.my-app.loadbalancer.server.port=8080

With these tags, and assuming the instance has the Name tag my-app, the provider creates an HTTP router matching Host(my-app.example.com) and a service whose backend targets the instance's private IP on port 8080.

Backend addressing

When a service does not set an explicit port tag, the port is resolved through securityGroupPortDiscovery if enabled; otherwise the service is ignored. HTTP services default to the http scheme unless a scheme or a full server URL is set through tags.

Provider Namespace

Resources discovered by the ec2 provider are created in the ec2 provider namespace. When referencing such a resource from another provider, suffix its name with @ec2:

<resource-name>@ec2

For more details on provider namespaces, see the providers overview.

Additional Notes

  • The service name is derived from each instance's Name tag, normalized. Multiple instances sharing the same Name are merged as servers behind the same load balancer.
  • Only instances in the running state are discovered.
  • Backends use the address selected by ipMode; instances without an address for the resolved mode are skipped.
  • The provider retries unsuccessful AWS API calls with exponential backoff and retains the last valid configuration until the next successful refresh.