mrkeyoor.com_
Sat 03 Oct 07:16 UTC
Self-Hostedevaluationupdated 03 Oct 2026

lunel review

Lunel is a self-hosted control panel for creating and managing VLESS, Trojan, and Shadowsocks proxy instances. One web console handles deployment, health checks, usage limits, logs, domains, and client links, while a worker runs each proxy core in a container or a restricted process.

Verdict

Our Lunel run installed 62 packages in 28 seconds and all 45 tests passed, but the project has no visible CI workflow or tagged GitHub release, so it is promising code with a short public operating record. Try it if the three supported proxy families are enough and you can deploy the Docker-isolated path with changed credentials. Do not put the zero-variable admin / admin setup on a public domain and call the job finished.

We ran it

Lab card: what happened when we ran lunelScreenshot of lunel (github.com/ArasTey/lunel)
Install✓ · 28s62 packages · 101 MB
Build✓ · 7s
Tests✓ · 69s45 passed · 0 failed of 45 (pytest)
Known vulns0(pip-audit)
Repo95 files~11,976 lines of source · 0.6 MB · 0 CI workflows · tests dir

Answers from our run

Does lunel build from source?

Dependencies installed in 28 seconds (62 packages), and the build succeeded in 7 seconds. We cloned commit df53d8b into a clean Debian container with 3 CPUs and no project-specific setup.

Do lunel's tests pass?

Yes: 45 of 45 passed when we ran the project's own test command (pytest). Some failures need services or credentials a bare container does not have.

Does lunel have known vulnerabilities in its dependencies?

pip-audit found none in the dependency tree at the time of our run.

Who should not use lunel?

Anyone likely to leave first-login defaults unchanged: the quick start publishes admin / admin and tells you to replace it immediately.

What are the alternatives to lunel?

3X-UI, Hiddify Manager, S-UI. Our Lunel run installed 62 packages in 28 seconds and all 45 tests passed, but the project has no visible CI workflow or tagged GitHub release, so it is promising code with a short public operating record.

Setup3/5Fast local install, but safe public setup adds storage, TLS, and secrets
Docs4/5Clear architecture, security, API, development, and deployment guides
Community2/51,001 stars, one open issue, and a very short public history
Maturity3/545 tests passed, but no CI workflow or tagged release is visible

Who it’s for

An individual operator who wants several proxy instances behind one web console and understands the protocols involved.
Python teams prepared to operate FastAPI services, persistent storage, TLS, and private worker networking.
Self-hosters who want Docker isolation and can generate, store, and rotate the console, worker, and instance secrets.
Developers migrating RVG-compatible client links who need the existing URL formats to keep working.

Who it’s NOT for

Anyone likely to leave first-login defaults unchanged: the quick start publishes admin / admin and tells you to replace it immediately.
Multi-tenant operators who require a separate credential per worker: the security document says all nodes currently share one worker token.
Teams treating process limits as equivalent to containers: Lunel calls the process driver weaker and reserves the Docker driver for production isolation.
Organizations that require tagged releases and visible CI before adoption: GitHub has no release object, and our scan found 0 CI workflow files.
Operators who cannot attach persistent storage: the zero-variable path stores SQLite under /data, so a stateless redeploy can lose the control-plane database.

Setup reality

Our Debian sandbox installed commit df53d8b in 28 seconds, adding 62 packages and using 101 MB. The build passed in 7 seconds. Pytest completed in 69 seconds with all 45 tests passing and 0 failures. Pip-audit reported 0 known vulnerabilities. The checkout itself contained 95 files, about 11,976 lines of source, and used 0.6 MB.

The simplest deployment starts python main.py on port 8080 with embedded SQLite and a generated secret. A public setup still needs HTTPS, persistent /data, and an immediate replacement for admin / admin. GitHub login requires an OAuth client ID, client secret, and matching public callback URL; PostgreSQL is optional for the unified path.

Managed hosting uses the weaker process driver. The documented production isolation path adds Docker, generated database and worker secrets, a TLS proxy, and optionally wildcard DNS. Split deployments must keep the worker private, and the shared worker token must match the console.

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.

Alternatives

ProjectWhat it isPick it when
3X-UI gh↗A mature Xray management panel with a wider list of protocols and users.pick this instead when broad Xray protocol coverage and an established panel community matter more than Lunel's small Python codebase.
Hiddify ManagerA multi-user proxy panel built around many anti-filtering protocols and deployment targets.pick this instead when you need more client and protocol options plus an older deployment ecosystem.
S-UI gh↗A web panel for managing sing-box services and users.pick this instead when sing-box is already your chosen runtime.

What people are saying

  1. [velocity-scout] ArasTey/lunel

Sources

  1. Lunel repository and README
  2. Measured commit df53d8b
  3. Lunel deployment guide
  4. Lunel security model
  5. Lunel architecture
  6. Lunel development and test guide

More self-hosted reviews

vodiwalker_panel · srs · FluxDown · life-recorder · bank-sampah · 3x-ui_runonflux · the whole board →