A subscription panel small enough to read before you trust it
🚀 SulgX Panel: A single-file, powerful, and free panel for managing VLESS subscriptions via WebSocket + TLS. Responsive UI, JWT auth, per-user bandwidth limits, clean IP scanner, bilingual Telegram bot, and real-time traffic charts. Runs smoothly on Render, Railway, Dockfly, and other cloud platforms.
At a glance
- What is it?
- This single-file FastAPI panel manages VLESS subscriptions with quotas, charts and a notification bot, deployed by forking onto free hosting. Its fork count dwarfs its stars, and its README contradicts the repository on both version and licence.
- Who is it for?
- This panel suits someone managing connections for themselves or a small group who values being able to read the whole application before trusting it with their traffic, and the single-module structure makes that a realistic afternoon rather than an aspiration. The authentication baseline is sensible, with rate limiting behind the login rather than only a password policy, and the quota and expiry controls cover what a small operator needs.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 52 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 18, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
An entire panel in one file
This is a self-hosted management panel for VLESS subscriptions carried over WebSocket with TLS. It handles user accounts, per-user traffic quotas and expiry, subscription links, traffic charts, a Telegram notification bot and an address scanner. The README states it is built entirely in a single Python file, on FastAPI with SQLite.
The repository tree supports that claim. Beside a licence, two README files, a configuration file and an image directory sit a Dockerfile, a process file, a platform configuration file, a requirements file, and one Python module.
For most projects a single file of that size would be a criticism. Here it is arguably the strongest thing about the design, and the reason is what this software does. A subscription panel holds account credentials, issues the configuration that clients connect with, and sits in the path of every byte its users send. Anyone deploying it is trusting it completely. A single file can be read start to finish in an evening by one person, which is a materially different proposition from auditing a framework application spread across forty modules.
The audience is someone running connections for themselves or a small group, on infrastructure they control, and the project's second README in Persian says plainly who that has largely been.
Deployment by fork, and what the fork count reveals
The deployment model is unusual and the README is direct about it. Fork the repository to your own account, connect the fork to a hosting platform, let the platform detect the Dockerfile and build it, then set environment variables in that platform's dashboard.
The repository's own numbers tell you how well that has worked. It reports 480 stars against 2,093 forks. That ratio is inverted from almost every other project, where forks are a fraction of stars, and it is the signature of software where forking is the installation procedure rather than the first step of contributing.
Five platforms are recommended, chosen on a criterion the README states openly: they support WebSocket, build from a Dockerfile, and require neither a credit card nor a phone number, only an email address or a GitHub account. Others are noted as working but requiring one of those.
That criterion is worth reading for what it implies about the users. Accessibility without payment credentials is a requirement for people in places where international cards are hard to obtain, which is the same population most likely to need this category of software at all.
Keeping secrets in the platform dashboard rather than in the repository is the right call and the necessary one, because a fork made through the web interface is public by default. The environment variable table in the README is how the administrator password and related settings arrive, and none of it lands in the fork.
The container build, and two things it does not do
The Dockerfile is short enough to read in full:
FROM python:3.11-slim
WORKDIR /app
RUN pip install --upgrade pip
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python", "main.py"]The dependency ordering is correct: requirements are copied and installed before the application, so the expensive layer is cached and a code change does not reinstall everything. That is the detail most hand-written Dockerfiles get wrong.
Two things are absent. The repository tree contains a git ignore file but no Docker ignore file, so the copy on the second-to-last line brings the entire build context into the image, including the version control directory when one is present in the context. On a platform that clones before building, that means repository history travels into the running image, which is wasted space and a larger surface than intended.
There is also no instruction to drop privileges, so the process runs as the container's root user. For a panel reachable from the internet that is worth knowing, even though the platforms this targets isolate containers themselves.
The requirements file pins exact versions for most dependencies, including the web framework, the server, the token library, the password hashing library and the rate limiter, which is the right discipline for a security-relevant application. Two entries use minimum-version constraints instead, and both an asynchronous SQLite driver and a PostgreSQL driver appear in the list, although the README describes SQLite. The README section shown does not explain when the second one is used.
Authentication, limits, and the audit trail
The security section lists a defensible baseline rather than a novel one, which for this category is the correct ambition.
Sessions use tokens held in cookies marked HTTP-only and secure, so client-side script cannot read them. Rate limiting is applied to logins and to interface calls, backed by a dedicated library in the requirements. Passwords are subject to a stated minimum length and character mix, and hashed with a purpose-built password hashing library rather than a general-purpose digest. Login attempts are logged with their outcome, source address and client string.
Each of those is a standard control, and the value is in their all being present at once. The common failure in self-hosted panels is not the absence of authentication but the absence of rate limiting behind it, which turns a weak administrator password into a matter of time.
On the account side, the panel offers per-user traffic limits in gigabytes, expiry in days, and a cap on concurrent connections, with bulk operations for activating, deactivating, resetting and deleting in batches. The default inbound is described as protected from deletion, which is the sort of guard that only gets added after someone has removed it by accident.
The user-facing dashboard includes a usage bar with colour thresholds, and the notification bot raises alerts on logins, expiries, errors and quota reaching ninety percent, in either English or Persian.
Keeping a free tier awake, and the cost of doing so
One feature deserves to be read more carefully than its section heading suggests.
Free hosting tiers suspend idle applications, which for a panel means connections stop working after a quiet period. The project's answer is a keep-alive engine with two modes selectable from the settings, a configurable interval, and behaviour the README describes as adjusting request headers and intervals automatically to avoid provider blocks.
That last clause describes working against the hosting platform's own resource management. Idle suspension is how these providers afford a free tier, and the phrase about avoiding blocks makes clear the provider is expected to object. Whatever a reader thinks about the merits, this is a feature whose success condition is the host failing to enforce its policy, and the honest framing is that it risks the account rather than being a neutral technical setting.
The related consideration is the traffic itself. A panel carrying real usage moves bandwidth through a platform that priced its free tier for a hobby project, and the README carries its own bandwidth and pricing section covering that question.
Anyone deploying this should read the terms of the platform they choose rather than the recommendation order in the README, because the account being terminated takes the configuration and the users with it.
The scanner, and whose networks it touches
The address management feature allows adding, editing and bulk-importing addresses attached to subscriptions, with a scanner that probes port 443 across twenty-four predefined cloud provider ranges.
Two design details are good. Large ranges are capped at 4,096 addresses so that a broad prefix does not freeze the browser, and public resolver addresses are excluded automatically. Both are the kind of guard that comes from watching people misuse a tool rather than from imagining it.
The part worth stating plainly is that this scans networks belonging to other companies. Probing a single port across provider ranges is at the mild end of network scanning and is unlikely to cause harm, but it is still unsolicited traffic to infrastructure the operator does not own, and several of those providers address it in their terms.
The cancellation behaviour noted in the changelog, where scanner tasks are cancelled when the connection closes, is the right fix for the obvious failure mode of a long scan continuing after the user has walked away.
For anyone evaluating the feature, the question is not whether it works but whether the scanning volume is something the operator wants attributed to their own address.
Two contradictions to resolve before deploying
The README presents itself as version 1.1.0, in its heading, its badge and its changelog table. The repository's published releases run considerably further, with the most recent tagged 1.5.7 on 2026-07-28, the same day as the last push, and two further releases published in the days before it. The README is several versions behind what the project actually ships, and its feature list should be read as a floor rather than a description of current behaviour.
The second contradiction matters more. The licence badge in the README declares a non-commercial licence, while the repository's own metadata reports MIT. Those are incompatible claims, since MIT places no restriction on commercial use. A licence file exists in the tree, and it is the file rather than either summary that governs. Anyone whose plans depend on the answer should open it first. This is not legal advice.
The release notes themselves contain only comparison links rather than descriptions, so the changelog table in the README is the only prose account of what changed, and it describes an older version.
The project reports no open issues, and the README's table of contents lists a strict disclaimer section covering the terms of use.
Before deploying, work through four things in order. Open the licence file and establish what it actually permits. Read the single Python module, since the whole point of that structure is that you can. Check the chosen platform's terms against both the keep-alive behaviour and the expected bandwidth. Then pin the deployment to a release tag rather than the default branch, which the README itself suggests for stability and which also means you know exactly what you are running.
Editorial conclusion
This panel suits someone managing connections for themselves or a small group who values being able to read the whole application before trusting it with their traffic, and the single-module structure makes that a realistic afternoon rather than an aspiration. The authentication baseline is sensible, with rate limiting behind the login rather than only a password policy, and the quota and expiry controls cover what a small operator needs. Open the licence file before anything else, because the README's non-commercial badge and the repository's MIT metadata cannot both be right, and read the README as describing version 1.1.0 while the project ships 1.5.7, so pin a release tag and check your platform's terms against the keep-alive behaviour before you rely on the deployment.
Frequently asked questions
How is SulgX Panel deployed?
By forking the repository, connecting the fork to a hosting platform, and letting it build the included Dockerfile. Settings including the administrator password are supplied as environment variables in the platform dashboard rather than committed to the fork.
Which hosting platforms does it target?
The README recommends five that support WebSocket, build from a Dockerfile, and need neither a credit card nor a phone number to register. Others are described as working but requiring one of those at signup.
What security controls does it include?
Token-based sessions in HTTP-only secure cookies, rate limiting on logins and interface calls, an enforced password policy with a minimum length and character mix, password hashing through a dedicated library, and audit logging of login attempts with outcome, address and client string.
What licence does it use?
The repository metadata reports MIT while the README badge declares a non-commercial licence, and those cannot both be accurate. A licence file is present in the repository and governs over either summary, so it should be read directly. This is not legal advice.
What is the keep-alive feature for?
Free hosting tiers suspend idle applications, which would interrupt service. The panel pings itself on a configurable interval in one of two modes, and the README states it adjusts headers and intervals to avoid provider blocks, which means working against the host's own idle policy.
Community notes