Describe the problem
When creating a Reverse Proxy service, the subdomain input in the dashboard silently strips any character that is not [a-z0-9-], including dots (.). This makes it impossible to create a service on a nested (multi-label) subdomain such as dev.app.example.com — typing the dot just deletes it, so you can only ever enter a single label (app.example.com).
The management API, however, accepts the full multi-label domain and provisions everything correctly: the ACME (TLS-ALPN-01) certificate is issued, the service becomes active, and requests are served / redirected to SSO as expected. So the UI is stricter than the backend, with no functional reason.
Root cause
src/modules/reverse-proxy/domain/ReverseProxyDomainInput.tsx — the subdomain field sanitizes input on change:
onChange={(e) =>
onSubdomainChange(e.target.value.toLowerCase().replace(/[^a-z0-9-]/g, ""))
}
/[^a-z0-9-]/g removes ., so nested subdomains can never be entered. A single DNS label is [a-z0-9-], but a subdomain may legitimately contain multiple dot-separated labels.
To reproduce
- Self-hosted NetBird with the Reverse Proxy feature and a connected proxy cluster whose base domain is e.g.
example.com (require_subdomain: false).
- Dashboard -> Reverse Proxy -> Services -> Add Service.
- In the subdomain field, try to type
dev.app (to get dev.app.example.com). The dot is stripped and you end up with devapp.
Compare with the API, which accepts it:
curl -X POST "https://<management>/api/reverse-proxies/services" \
-H "Authorization: Token <PAT>" -H "Content-Type: application/json" \
-d '{
"name": "dev-app",
"domain": "dev.app.example.com",
"mode": "http",
"enabled": true,
"targets": [{
"target_id": "<clusterId>", "target_type": "cluster",
"protocol": "http", "host": "backend.internal", "port": 80,
"enabled": true, "options": { "direct_upstream": true }
}],
"auth": { "bearer_auth": { "enabled": true, "distribution_groups": [] } }
}'
# -> 201, meta.status "pending" -> "active"; cert issued for dev.app.example.com;
# visiting https://dev.app.example.com redirects to the IdP for SSO.
Expected behavior
The subdomain input should allow multi-label subdomains (dot-separated labels), matching what the management API already accepts. Validation should permit a dot-separated sequence of DNS labels (e.g. ^[a-z0-9-]+(\.[a-z0-9-]+)*$) instead of stripping . entirely.
Actual behavior
Dots are removed on input, so nested subdomains cannot be created from the dashboard; the only workaround is the REST API.
Are you using NetBird Cloud?
No, self-hosted.
NetBird version
Management/proxy v0.72.x, dashboard v2.39.0.
Describe the problem
When creating a Reverse Proxy service, the subdomain input in the dashboard silently strips any character that is not
[a-z0-9-], including dots (.). This makes it impossible to create a service on a nested (multi-label) subdomain such asdev.app.example.com— typing the dot just deletes it, so you can only ever enter a single label (app.example.com).The management API, however, accepts the full multi-label domain and provisions everything correctly: the ACME (TLS-ALPN-01) certificate is issued, the service becomes
active, and requests are served / redirected to SSO as expected. So the UI is stricter than the backend, with no functional reason.Root cause
src/modules/reverse-proxy/domain/ReverseProxyDomainInput.tsx— the subdomain field sanitizes input on change:/[^a-z0-9-]/gremoves., so nested subdomains can never be entered. A single DNS label is[a-z0-9-], but a subdomain may legitimately contain multiple dot-separated labels.To reproduce
example.com(require_subdomain: false).dev.app(to getdev.app.example.com). The dot is stripped and you end up withdevapp.Compare with the API, which accepts it:
Expected behavior
The subdomain input should allow multi-label subdomains (dot-separated labels), matching what the management API already accepts. Validation should permit a dot-separated sequence of DNS labels (e.g.
^[a-z0-9-]+(\.[a-z0-9-]+)*$) instead of stripping.entirely.Actual behavior
Dots are removed on input, so nested subdomains cannot be created from the dashboard; the only workaround is the REST API.
Are you using NetBird Cloud?
No, self-hosted.
NetBird version
Management/proxy v0.72.x, dashboard v2.39.0.