Skip to content

Docker: hiddify apply and the panel's "Apply Changes" never run after container start, because daemons inherit the 0-install.lock file descriptor #5655

Open

Description

@serj95reg

Bug/Feature:

Description: Docker: hiddify apply and the panel's "Apply Changes" cannot run after the container has started, because every daemon inherits the 0-install.lock file descriptor and keeps the lock held.

Details:

Hiddify Version: 14.1.0b2
Python Version: 3.13.18 (main, Oct 26 2026, 14:08:20) [Clang 23.1.3 ]
OS: Linux-6.8.0-117-generic-x86_64-with-glibc2.39
User Agent: Unknown

Setup

Docker, docker-compose.yml from dev (network_mode: host), image ghcr.io/hiddify/hiddify-manager:beta (rev 29036f70b7). The relevant code (set_lock and the systemctl shim) is identical in dev and main.

Problem

After the container has started, hiddify apply always fails, although no install/apply is running:

$ docker exec hiddify-manager-hiddifymanager-1 hiddify apply --no-gui
Another installation is running.... Please wait until it finishes.

The panel is affected too. Its Apply API (start_action in apply_api.py) calls check_can_start, which aborts with 409 "Another action is still running", because _lock_held("0-install") is true while the daemons hold the descriptor. In the admin UI (Apply & Status) the card keeps showing the previous "Reinstall finished, 100%, 0:00" and nothing is applied (I did not trace why the UI shows that instead of the error).

The only way to apply settings is to restart the container, which re-runs the apply at boot.

Cause

set_lock (scripts/common/utils.sh) does exec {HIDDIFY_LOCK_FD}>"$(lock_file "$1")" and flock -n on it. The descriptor is inheritable and nothing closes it for child processes. Services are started through the bundled systemctl shim (services/docker/systemctl), which uses os.fork() + os.setsid() + os.execve() in execve_from() and never closes inherited descriptors, so every daemon keeps the lock open after the apply has finished (an flock is released only when all copies of the open file are closed).

Holders of the lock file in a running container (fd 10):

rpxy-l4, haproxy, xray, hiddify-core, telemt, usque, granian (panel)
/proc/locks: FLOCK ADVISORY WRITE, owned by hiddify-core

with_lock already passes flock -o to avoid this; set_lock does not.

Suggested fix (not tested)

  1. In the shim's execve_from(), close inherited descriptors before os.execve, e.g. os.closerange(3, 1024).
  2. Or close the lock descriptor when starting services (systemctl ... {HIDDIFY_LOCK_FD}>&-), or call remove_lock before daemons are started.
  3. Make the UI show the 409 error instead of the previous run's "finished" state.

Workaround

docker compose restart hiddifymanager

Activity

  1. added
    bugSomething isn't working
    usefulTriaged: real bug or improvement worth keeping
    need_attentionImportant: broken current release, security or widespread impact
    on Oct 29, 2026
  2. hiddify-com commented on Oct 29, 2026

    @hiddify-com
    Collaborator

    @hiddify-com Thanks for the detailed analysis. Flagging this: in Docker (14.1.0b2), daemons inherit the 0-install.lock descriptor from set_lock, so hiddify apply and the panel's Apply Changes are blocked until the container restarts. Workaround for now: docker compose restart hiddifymanager.

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

    bugSomething isn't workingneed_attentionImportant: broken current release, security or widespread impactusefulTriaged: real bug or improvement worth keeping

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions