One port can run the console, worker, and proxy cores
Lunel's easiest path is genuinely compact. Start python main.py, expose port 8080 through HTTPS, and the process launches the web console plus an internal worker. That worker creates Lunel Core instances as child processes, and the public gateway sends traffic from a per-instance endpoint token to the correct core. SQLite and generated secrets let the service boot without a database provisioner or OAuth application.
The console covers the work that becomes tedious with hand-managed proxy configs: create an instance, wait for health checks, issue compatible client links, inspect traffic, set expiry or quota limits, rotate an endpoint token, and stop or redeploy the runtime. The frontend is plain JavaScript with no build step. Under it, 11,976 lines of Python implement the console, worker, and VLESS, Trojan, and Shadowsocks relay paths.
The three protocol families share one control plane
Lunel Core supports VLESS and Trojan over WebSocket or xHTTP, plus Shadowsocks AEAD over WebSocket. Its links remain compatible with the RVG Gateway project from which the relay engine was derived. This is a focused set next to panels that cover many Xray or sing-box modes, but the narrower surface is easier to trace through a 95-file repository.
The architecture document gives concrete reasons for the refactor. xHTTP sessions use both the link identity and session ID, request and sequence buffers have caps, and quota accounting is shared across transports. Management endpoints require a per-instance bearer token. Public protocol routes still depend on their VLESS UUID, Trojan password, or Shadowsocks key, with an additional rotatable token in the URL path before traffic reaches them.
What happened when we ran it
Our sandbox installed commit df53d8b in 28 seconds with Python 3.12, 3 CPUs, 8 GB of RAM, no secrets, and no elevated privileges. The install added 62 packages and occupied 101 MB. The build finished successfully in 7 seconds. Pip-audit found 0 known vulnerabilities in the environment we created.
Pytest then ran for 69 seconds and passed all 45 tests, with 0 failures. The repository's tests cover protocol handling, streaming relays, backup behavior, subscriptions, and a local end-to-end path. That result says the supplied suite was green in our fresh Debian container. It does not measure proxy throughput, resistance to hostile traffic, or behavior behind a particular hosting provider's WebSocket edge.
Our scan found a tests directory but 0 CI workflow files. The green local result is useful, yet GitHub does not show an automated check repeating those 45 tests for every change. There is also no root Dockerfile in the harness signal. Lunel keeps its console and worker Dockerfiles under deploy/docker, matching the documented self-hosted route rather than the one-service root path.
The zero-variable login needs an immediate password change
The README's fastest flow tells you to sign in with admin / admin. The deployment guide repeats the warning to change that password on first login and documents LUNEL_DEFAULT_ADMIN=0 for disabling the seeded account. If a generated public domain becomes reachable before that change, anyone who knows the documented default can try it. Put credential replacement in deployment automation, not in a note for later.
GitHub OAuth removes that shared-password path, but it is not zero configuration. You need a client ID, client secret, correct callback address, secure cookies, and an accurate public URL. Sessions are opaque 256-bit values whose hashes are stored server-side, mutating requests repeat the session token in a CSRF header, and the default session lifetime is 7 days. These are sensible controls, provided the production environment variables match the public deployment.
Docker isolation is stronger than the managed-hosting shortcut
The unified managed-platform mode runs cores as separate processes with memory, CPU, and file-size limits. Lunel's own security document labels that driver weaker. Its Docker driver drops Linux capabilities, prevents privilege escalation, uses a read-only root filesystem, caps processes and resources, and publishes core ports only to loopback. That is the path to prefer when unrelated users or configs share a host.
Docker adds work. The documented stack requires generated PostgreSQL, session, and worker secrets; a TLS proxy; persistent data; and an image for the core. Enabling container control also gives the worker access to the Docker socket, although core containers do not receive it. In a split deployment, the worker has no public domain and should sit on a private network. The guide correctly warns that missing DNS alone is not access control.
One limitation matters if the deployment grows past one operator: workers share a single LUNEL_WORKER_TOKEN. The security guide calls per-node tokens a future need for multi-tenant use. A leaked shared token therefore has a wider blast radius than a node-specific credential would. Endpoint and core tokens reduce other paths, but they do not change that worker trust model.
October activity is current, while releases and CI are absent
GitHub records the latest push on October 2, 2026, one day before this review. The repository had 1,001 stars, 2,398 forks, and one open issue, which was a greeting rather than a defect report. Those figures show attention, but the project itself was created on September 9, 2026. It has weeks of public history, not years of upgrades and incident reports.
There is no latest GitHub release to pin, and the deployment guide's version fields default to 1.0.0, dev, and unknown unless the operator supplies values. Pin commit df53d8b for the exact 45-test result we saw, replace the default login before exposure, and prefer Docker when isolation matters. Lunel earns a trial because the measured suite is clean and the security trade-offs are written down. Its missing release and CI trail still make a cautious pilot the sensible first deployment.

