Live Xray log viewer on the node page

## The problem

Right now, looking at a node’s Xray log means SSH-ing into that node. The Panel already knows the node, is already authenticated to it, and already talks to it over an authenticated channel — but for the one thing you need most while debugging (“what is this node actually doing right now?”), it sends you to a terminal.

This gets worse the more nodes you run. Reproducing a user’s problem means: find which node they’re on, find its IP, SSH in, remember where the log went, `tail -f`, grep. Every time.

## The ask

A **Logs** tab on the node detail page. Live tail of that node’s Xray log, with a text filter. That’s it.

```

2026/08/09 16:09:28 from 1.2.3.4:23311 accepted tcp:docs.google.com:443 [my-reality → residence] email: 2

2026/08/09 16:09:38 from 1.2.3.4:23339 accepted udp:rr4—sn-qja5mc-5h.googlevideo.com:443 [my-reality → residence] email: 2

```

Being able to see that line live answers, in seconds, questions that currently take a round trip to a shell:

- Is this user’s traffic actually reaching the node, or dying before it?

- Is my routing doing what I think? (` → ` vs `>>` in `[inbound → outbound]` tells you whether a rule matched or it fell through to the default.)

- Is that new inbound receiving anything at all?

- Why is one user’s traffic going out the wrong outbound?

## What this is *not*

Scope creep is the obvious risk here, so to be explicit — I am **not** asking for:

- :cross_mark: log storage or search history

- :cross_mark: alerting, rules, thresholds, notifications

- :cross_mark: log aggregation across nodes

- :cross_mark: analytics, dashboards, per-user reports

Just an ephemeral stream. Open the tab, see what is happening now, close it, nothing is kept. Think Docker Desktop’s *Logs* tab, not a SIEM.

Everything above already has better tools if someone wants it (Loki/Promtail, and Torrent Blocker already covers the “notify me” case). The gap is specifically the *interactive, right now* view.

## Why it should be small to build

Most of the pieces are already there:

- **Transport** — Panel↔Node already have an authenticated HTTP channel (`SECRET_KEY` / `NODE_PORT`). An SSE endpoint next to the existing ones in `src/modules/xray-core/xray.controller.ts` fits the existing shape.

- **The Node already knows where its logs go.** It hands Xray the full config over the internal socket (`-config @${INTERNAL_SOCKET_PATH}:/internal/get-config`), so it can pick the right source with no user configuration:

- `log.access` empty → read from the s6 pipe (`xray/run` already does `exec 2>&1` into the `xray-log` consumer)

- `log.access` set to a file → tail that file

This matters: people who have already pointed `log.access` at a file (to get persistence and logrotate, since `s6-log -b n0` keeps no archives) would otherwise be locked out of the feature. Handling both means it just works either way.

- **No storage, no queue, no migration.** The Panel side is an `EventSource` and a scrolling buffer.

## Security — opt-in via env

It should be **off by default** and enabled explicitly on the node, e.g.:

```yaml

environment:

  • ENABLE_LIVE_LOGS=true

```

and the Node returns 403 on the endpoint unless it is set.

The Node config schema already has exactly this pattern, so it’s a three-line addition (`src/common/config/app-config/config.schema.ts`):

```ts

DISABLE_HASHED_SET_CHECK: z

.string()

.default('false')

.transform((val) => val === 'true'),

```

and `init-env.sh` already conditions behaviour on optional env (`CUSTOM_CORE_URL`), so this doesn’t introduce a new mental model.

To be clear about the reasoning: this is **not** about protecting users from the admin. An admin with SSH on the node can already `tail` the file — this feature doesn’t change what they’re capable of. The reasons for the switch are different:

1. **Defence in depth.** If the Panel is ever compromised (XSS, stolen session, weak password), the attacker should not automatically also get a live traffic feed from every node. SSH is a separate credential and a separate door; a Panel tab is free.

2. **Separation of roles.** Panel admin and node owner aren’t always the same person (resellers, managed nodes, a friend’s spare box). Enabling it by default makes that decision for them.

3. It sidesteps the “should this be on by default?” debate entirely.

The **Create Node** wizard could carry a checkbox that adds the env line to the generated `docker-compose.yml`, so it costs nothing at setup time — consistent with how the wizard already generates the compose file for you.

## Nice to have (not required)

- Filter box (client-side substring match is enough)

- Pause / resume

- Copy visible buffer

- Line cap (e.g. keep last 1–2k lines in the browser)

Happy to hear if this overlaps with something already planned, or if the preferred direction is different (e.g. a CLI command rather than a Panel tab). The core need is just: *see a node’s live Xray log without SSH-ing into it.*

6 Likes