Skip to content

"User Configs" builtin proxy is silently disabled whenever HTTP (non-TLS) proxies are turned off #5622

Closed

Description

@MiladMazaheriPuls

Summary

Per-user Additional configs (Users → edit → Additional configs) never show up in any subscription format if the global setting HTTP proxies (http_proxy_enable) is off. There's no warning in the UI and nothing in the logs. The builtin user-configs proxy is turned off without any message.

Steps to reproduce

  1. Make sure http_proxy_enable is off. That's the safe default for many people, because plain-HTTP proxies are easy to detect.
  2. Edit a user → Additional configs → add an offline row, e.g. target sublink with a vless://… share link.
  3. Open that user's subscription (/<client_path>/<uuid>/sub64/), or run
    hiddifypanel dump-client-configs --user-uuid <uuid> /tmp/dump.

Expected: the extra link is in the subscription.
Actual: it's missing from every format: sublink, xray, hiddify-core, singbox, clash.

Root cause

The builtin preset gives the client-only user-configs proxy (mode no_inbound) the TLS layer http:

hiddifypanel/proxy_v3/template_catalog/custom_proxy_presets.py (user-configs preset, around line 298):

proto="vless",
transport="other",
tls_layer="http",          # <- this
categories=("user_configs",),

CustomProxy.enable is a hybrid property that also checks the global switches:

hiddifypanel/models/custom_proxy.py:450-451

@hybrid_property
def enable(self) -> bool:
    return bool(self._enable) and not self.blocked_parent_enables()

and the switch for TlsLayer.http is http_proxy_enable:

hiddifypanel/proxy_v3/context_vars/builder/utils.py:96

tls_layer_config_map = {
    TlsLayer.http: ConfigEnum.http_proxy_enable,
    ...

So with http_proxy_enable = false, user-configs.enable is False, even though the DB column enable is 1. get_bases() skips it at client_builder.py:73 (if not p.enable: continue), so user_additional_configs() never runs.

The user-configs proxy has no inbound and carries no plain-HTTP traffic, so the HTTP switch shouldn't apply to it.

Workaround (what I did)

I overrode only the tls_layer of the builtin user-configs proxy to tls, saved as a builtin override so the next catalog sync keeps it. tls isn't in tls_layer_config_map, so nothing gates it any more, and http_proxy_enable stays off.

# hiddifypanel shell
from hiddifypanel.database import db
from hiddifypanel.models.custom_proxy import CustomProxy
from hiddifypanel.proxy_v3.template_catalog.custom_proxy_builtin import set_field_override, _apply_live, ensure_builtin_migrated
from hiddifypanel.cache import cache

p = CustomProxy.query.filter_by(slug="user-configs").first()
ensure_builtin_migrated(p)
set_field_override(p, "tls_layer", True)
_apply_live(p, "tls_layer", "tls")
db.session.commit()
cache.invalidate_all_cached_functions()
print(p.enable)  # True

After this, the sublink and xray formats contain the user's additional configs. The hiddify-core / singbox formats still didn't, because of Issue 2.

Suggested fix

Any of these would work:

  • Don't apply parent_enable_keys to no_inbound proxies, or at least not the TLS-layer key.
  • Give the user-configs preset a layer that isn't gated, or None.
  • At minimum, show blocked_by for builtin client-only proxies in the UI, so admins can see why their Additional configs vanished.

The telegram-web builtin (no_inbound too) isn't affected on my install, which suggests this is only about the layer value chosen for user-configs.


Activity

  1. MiladMazaheriPuls commented on Oct 18, 2026

    @MiladMazaheriPuls
    Author

    Issue 2: Additional configs are always empty in the hiddify-core / sing-box output (user_configs.j2 sets a variable outside the blocks)

    Summary

    Even with Issue 1 worked around, a user's Additional configs show up in the sublink and xray outputs, but never in hiddify-core / singbox JSON. That's the format the Hiddify app downloads, so Hiddify-app users never see their Additional configs.

    Steps to reproduce

    1. Work around Issue 1 (or turn on http_proxy_enable).
    2. Add an offline Additional config row for a user with target hiddify-core (or auto) and a sing-box document such as:
      {"outbounds": [{"type": "vless", "tag": "my extra", "server": "example.com", "server_port": 443, "uuid": "...", "tls": {"enabled": true, "server_name": "example.com"}, "transport": {"type": "ws", "path": "/x"}}]}
    3. hiddifypanel dump-client-configs --user-uuid <uuid> /tmp/dump, then grep "my extra" /tmp/dump/*.

    Expected: hiddify-core.json and singbox.json contain the outbound.
    Actual: sublink.txt and xray.json contain the user's rows, but hiddify-core.json and singbox.json contain nothing.

    On my install, user_additional_configs("hiddify-core") called directly from hiddifypanel shell for the same user returns the parsed document. So the data and parser are fine, and the problem is in the template.

    Root cause

    hiddifypanel/proxy_v3/proxy_templates/hiddify-core/client/user_configs.j2:

    {% set user_configs = user_additional_configs("hiddify-core") %}   {# line 5: outside any block #}
    {% block outbounds %}
         {% for conf in user_configs if conf %}                          {# always empty here #}
              {% for outbound in remote_proxy_outbounds(conf, "hiddify-core") %}
                   {{ outbound | tojson }},
              {% endfor %}
         {% endfor %}
    {% endblock %}
    
    {% block endpoints %}
         {% for conf in user_configs if conf %}
         ...

    The client templates are rendered block by block (outbounds, endpoints), and a Jinja block can't see a variable set at the top level outside it. So user_configs is undefined inside both blocks, and the loops produce nothing.

    The xray version (proxy_templates/xray/client/user_configs.j2) calls user_additional_configs("xray") inside its block, which is why the xray output works.

    Workaround (what I did)

    I overrode the builtin's hiddify-core client template (client:hiddify-core builtin override) with the same template, but calling the function inside each block:

    {% block outbounds %}
         {% for conf in user_additional_configs("hiddify-core") if conf %}
              {% for outbound in remote_proxy_outbounds(conf, "hiddify-core") %}
                   {{ outbound | tojson }},
              {% endfor %}
         {% endfor %}
    {% endblock %}
    
    {% block endpoints %}
         {% for conf in user_additional_configs("hiddify-core") if conf %}
              {% for endpoint in remote_endpoints(conf) %}
                   {{ endpoint | tojson }},
              {% endfor %}
         {% endfor %}
    {% endblock %}
    # hiddifypanel shell
    from hiddifypanel.proxy_v3.template_catalog.custom_proxy_builtin import client_override_key
    p = CustomProxy.query.filter_by(slug="user-configs").first()
    ensure_builtin_migrated(p)
    key = client_override_key("hiddify-core")
    set_field_override(p, key, True)
    _apply_live(p, key, open("/tmp/fixed_user_configs.j2").read())
    db.session.commit()
    cache.invalidate_all_cached_functions()

    After this, hiddify-core.json / singbox.json contain the extra outbound, and it shows up in the Select / Auto groups. I confirmed it in the Hiddify app on Windows: the additional config is listed and connects.

    Suggested fix

    In proxy_templates/hiddify-core/client/user_configs.j2, move the user_additional_configs("hiddify-core") call inside each block, as above. The xray template already does this. Assigning to a variable inside each block would also work.


  2. MiladMazaheriPuls commented on Oct 18, 2026

    @MiladMazaheriPuls
    Author

    Other v14 problems I noticed

    • Old admin UI crashes after upgrading to v14: werkzeug BuildError: Could not build url for endpoint 'admin.Dashboard:index'. The legacy Dashboard view is only registered when log_level == debug (panel/admin/__init__.py), but the legacy flask-admin list pages (/admin/user/ etc.) are still registered, and templates/admin-layout.html line 99 still links to admin.Dashboard:index.
    • Per-ISP cdn_ip selection is cached across users: get_availble_domains(sublink_domain) is @cache.cache(600) keyed only by the sub-link domain. The ISP-based IP picked for the first requester is served to every user, whatever their ISP, for 10 minutes.
    • LookupError: 'telegram' is not among the defined enum values. Enum name: fakemode: the DB enum for domain.fake_mode includes telegram/shadowtls/ssfaketls, but some query path still uses an ORM enum with only valid, fake, reality, dns.
    • Not a bug, but it surprised me: as soon as any domain is sub_link_only, get_availble_domains() returns [] for subscriptions fetched through any other domain, so those subscriptions come back empty. A UI warning would help.
  3. armanoboganesyan-stack commented on Oct 18, 2026

    @armanoboganesyan-stack

    Hi, there! In attachment, exactly same issues that you wrote about, and how to fix it. I have fix its with cloud in v13.0.3, then v14.0.0 and then 14.0.1. In v14.0.2 - it not fixed yet.

    hiddify-bug-report.md

    #5596

  4. added
    usefulTriaged: real bug or improvement worth keeping
    on Oct 25, 2026
  5. hiddify-com commented on Oct 27, 2026

    @hiddify-com
    Collaborator

    Fixed in hiddify/HiddifyPanel-old@7518b20 (dev branch, after v14.1.0b1; not in a stable or beta release yet): User Configs are no longer gated by the HTTP proxies switch, and Additional configs now render in hiddify-core/sing-box output. If it still happens on the latest version once this ships, please reopen this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    usefulTriaged: real bug or improvement worth keeping

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions