← Docs

Internal apps

Open internal HTTP dashboards (Grafana, an admin panel, a status page…) through the same outbound tunnel — no VPN and no inbound ports. Subnomic reverse-proxies the dashboard at an authenticated URL.

Apps are registered and opened from the console at app.subnomic.com.

Register an app

  1. Go to Internal apps → New app.
  2. Name it, choose the host or tunnel agent that can reach it.
  3. Set scheme (http/https), host and port (e.g. http 127.0.0.1:3000).
  4. Optionally set a base path.
  5. Create, then click Open — the dashboard opens in a new tab, proxied through the agent.
Some apps hard-code absolute asset paths (e.g. /static/...). Those may not render perfectly under the proxy unless they support a base path / X-Forwarded-Prefix setting. Subnomic forwards X-Forwarded-Prefix to help.

Examples

Common internal tools and how you'd register them:

Grafana        http   127.0.0.1:3000
Prometheus     http   127.0.0.1:9090
RabbitMQ UI    http   127.0.0.1:15672
Kibana         http   127.0.0.1:5601
Argo CD        https  argocd-server.argocd.svc:443
The chosen agent must be able to network-reach the host:port (it dials it with net.Dial). To reach a service that only lives inside a Kubernetes cluster, run a tunnel agent (MODE=tunnel, no shell) in the cluster and point the app at the service DNS, e.g. nginx.default.svc.cluster.local:80.

Require approval (optional)

Tick Require approval to connect in the New app form to gate it behind just-in-time access. Users then see a Request access action (and Break-glass, if permitted) until a grant is approved. See Access requests.

Raw TCP services

Non-HTTP TCP services (a message broker, a custom port) ride the same tunnel, but reaching them from a browser is not possible — that needs a local proxy client, which is planned but not in this release.

Editing

Use Edit on an app row to change the agent, scheme, host, port, base path or the approval gate without recreating it.

Troubleshooting

  • "proxy error: dial tcp … i/o timeout" — wrong port or host. The new-app form defaults to port 8080; set the service's real port (e.g. 80). Confirm the agent can reach it.
  • Page renders broken (missing CSS/JS) — the app hard-codes absolute asset paths. Set a base path / have it honor X-Forwarded-Prefix.
  • No agent in the picker — register a host or tunnel agent that can reach the app first.
  • "approval required" — the app is gated; use Request access / Break-glass, then reopen.

Permissions

app.read app.connect app.manage