One cloudflared instance, unlimited services

cloudflared is the client that powers Cloudflare's Argo Tunnel, letting you expose local services such as websites, APIs, or TCP servers through Cloudflare's edge. The tunnel works by having cloudflared hold long-lived connections to Cloudflare; when traffic arrives for your hostname, it is proxied down those connections and onward to the local service. That design keeps all traffic in front of Cloudflare's security and caching layers, and gives you the option to enforce Zero Trust access policies instead of relying on VPNs or firewall rules.

Large deployments have long hit a hard ceiling with this model: each cloudflared process could only proxy a single service. A customer running 100 services needed 100 cloudflared instances, multiplying resource use and complicating service management. With the release of ingress rules, that limit is gone—you can now route unlimited services through one cloudflared process, at no additional cost, using Named Tunnels.

Named Tunnels review

Named Tunnels are instances with stable IDs, so you can start and stop them without having to re-create DNS or Load Balancer records. Traffic enters the tunnel via a DNS record or Cloudflare Load Balancer, and ingress rules inside the cloudflared configuration determine which local service receives each request.

Set up a tunnel with:

$ cloudflared tunnel create my_tunnel_name

Then point DNS or a Load Balancer at it. Ingress rules do the rest.

Ingress rules

An ingress rule maps an internet URL to a local service, and rules are listed under the ingress key of the config file:

$ cat ~/cloudflared_config.yaml

tunnel: my_tunnel_name
credentials-file: .cloudflared/e0000000-e650-4190-0000-19c97abb503b.json
ingress:
 # Rules map traffic from a hostname to a local service:
 - hostname: example.com
   service: https://localhost:8000
 # Rules can match the request's path to a regular expression:
 - hostname: static.example.com
   path: /images/*\.(jpg|png|gif)
   service: https://machine1.local:3000
 # Rules can match the request's hostname to a wildcard character:
 - hostname: "*.ssh.foo.com"
   service: ssh://localhost:2222
 # You can map traffic to the built-in “Hello World” test server:
 - hostname: foo.com
   service: hello_world
 # This “catch-all” rule doesn’t have a hostname/path, so it matches everything
 - service: http_status:404

Beyond plain addresses, a rule can return a fixed HTTP status code or respond with the built-in Hello World test server. The full set of supported services is documented in the ingress configuration reference.

Matching is based on hostname, a path regex, or both. Suppose a rule has no filters—it then matches everything, so a single rule can apply to DNS records from multiple zones that route into the same tunnel. Evaluation is top-to-bottom: the first matching rule wins. The final rule is required to match all remaining traffic, so cloudflared always has a response path when no earlier rule applies.

Validating and previewing rules

Before you put a config into production, you can check the syntax:

$ cat ~/cloudflared_config_invalid.yaml

ingress:
 - hostname: example.com
   service: https://localhost:8000

$ cloudflared tunnel ingress validate
Validating rules from /usr/local/etc/cloudflared/config.yml
Validation failed: The last ingress rule must match all URLs (i.e. it should not have a hostname or path filter)

That command verifies that the regexes are valid, that every service target is valid, and that the last rule (and only the last rule) matches all traffic.

To check which rule a given URL will hit, run a dry-run-style preview:

$ cloudflared tunnel ingress rule https://static.example.com/images/dog.gif
Using rules from ~/cloudflared_config.yaml
Matched rule #2
        Hostname: static.example.com
        path: /images/*\.(jpg|png|gif)

No tunnel is started and no request is sent. This is a quick way to confirm the right URLs go to the right services.

Per-origin settings

Not every local service needs the same treatment when cloudflared proxies a request to it. You might want different timeouts or HTTP headers for different origins. cloudflared lets you set a default block of origin settings and override individual keys per rule:

ingress:
  # Set configuration for all services
  originRequest:
    connectTimeout: 30s
 # This service inherits all the default (root-level) configuration
 - hostname: example.com
   service: https://localhost:8000
 # This service overrides the default configuration
 - service: https://localhost:8001
   originRequest:
     connectTimeout: 10s
     disableChunkedEncoding: true
 # Catch-all rule doesn’t actually use any of the config
 - service: http_status:404

The full set of tunable options is in the Argo Tunnel configuration docs. Ingess rules are designed to make running many services through one tunnel practical, both for resource efficiency and for day-to-day operational sanity.