Add Path Rule
fibe.gg/path_rule lets two or more services share a subdomain by partitioning HTTP traffic on the URL path. Common case: one service answers /cable and /health; another answers everything else.
Allowed matchers
ONLY these three Traefik matchers, in any boolean combination with && and ||:
Path(`/exact/url`)PathPrefix(`/prefix`)PathRegexp(`/users/[0-9]+`)
Schema check: value must contain \b(?:Path|PathPrefix|PathRegexp)\s*\(.
Forbidden matchers
Fibe owns the Host rule, so these matchers are explicitly rejected by both schema and runtime:
Host(...),HostRegexp(...),HostSNI(...),HostSNIRegexp(...)Headers(...),HeadersRegexp(...)Method(...),Query(...),ClientIP(...)
Schema check fails with: must only contain path matchers, not Host/Headers/Method/Query/ClientIP.
Examples
One specific path, one catch-all
services:
web:
labels:
fibe.gg/expose: external:3000
fibe.gg/subdomain: app
# no fibe.gg/path_rule — catch-all on app.<root>
api:
labels:
fibe.gg/expose: external:8080
fibe.gg/subdomain: app # same subdomain
fibe.gg/path_rule: PathPrefix(`/api`)
https://app.<root>/api/... → api service. Everything else → web.
Multiple paths combined
services:
ws:
labels:
fibe.gg/expose: external:8081
fibe.gg/subdomain: app
fibe.gg/path_rule: Path(`/cable`) || Path(`/health`) || PathPrefix(`/ws`)
This sends /cable, /health, and /ws... requests to the websocket service while keeping the rest of the host on the main web service.
Path regex
services:
legacy:
labels:
fibe.gg/expose: external:5000
fibe.gg/subdomain: app
fibe.gg/path_rule: PathRegexp(`/v[0-9]+/legacy/.*`)
Backticks vs quotes in path arguments
Traefik's official syntax uses backticks around the path literal: Path(`/foo`). Single or double quotes would be ambiguous with YAML and JSON. Always use backticks.
In YAML, the entire label value is a string, so backticks need no escaping:
fibe.gg/path_rule: Path(`/cable`) || Path(`/health`)
If you need to template-interpolate inside the literal, mix in $$var__NAME:
fibe.gg/path_rule: PathPrefix(`/$$var__PATH_PREFIX`)
The schema's templatedString rule allows variable markers anywhere in the string.
Boolean combinations
| Combination | Meaning |
|---|---|
Path(/a`) | |
Path(/a) && PathPrefix(/sub) | matches /a AND URL begins with /sub (rare; && of Path() makes little sense) |
(Path(/a`) |
In practice, || between Path() / PathPrefix() / PathRegexp() is the only combination needed.
Pattern: catch-all web + specific ws
This is the most common multi-service-per-subdomain pattern:
services:
web: # default route
labels:
fibe.gg/expose: external:3000
fibe.gg/subdomain: $$var__SUBDOMAIN
# no path_rule
ws: # specific
labels:
fibe.gg/expose: external:8081
fibe.gg/subdomain: $$var__SUBDOMAIN
fibe.gg/path_rule: Path(`/cable`) || Path(`/health`)
Traefik's matchers prefer the more specific rule, so ws wins on /cable and /health; web wins elsewhere.
Pitfalls
- No path matcher at all — value like
Host(foo.bar)is rejected. Value MUST containPath,PathPrefix, orPathRegexp. - Wrong quote style —
Path('/api')orPath("/api")aren't valid Traefik. Use backticks. - Trailing slash mismatch —
PathPrefix(/api)matches/apiand/api/x.Path(/api)matches ONLY/api. Know which you want. - Trying to route by Host or Method — Fibe owns host; the validator rejects. If you need method-based routing, do it in the app.
- Two services with same
path_rule— only one wins; you'll see flapping. Make the rules disjoint. - Forgetting
fibe.gg/path_ruleisreq_exposed— required-when-exposed in the schema annotation, but the schema doesn't enforce it (presence-only requirement). Set it explicitly when sharing a subdomain.
Related skills
recipe-add-subdomain, decide-exposure-strategy, recipe-inline-variables, reference-fibe-labels, playbook-rails-app.