From cb93a1f0d39791e7f1dd6df5c56037c47dbb778e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 24 May 2026 06:39:38 +0000 Subject: [PATCH] fix: support non-root user container startup - Guard /etc/resolv.conf write and crond behind root check in entrypoint; non-root containers now stay alive via 'tail -f /dev/null' instead of failing when crond exits with EPERM - Set PM2_HOME to ${QL_DIR}/data/.pm2 (inside the data volume) so PM2 does not fall back to /root/.pm2, which is inaccessible to non-root users - Pre-create /ql/.tmp and /ql/shell/preload during image build and make them world-writable so non-root processes can write runtime files - Wrap directory creation in initFile.ts with try/catch + recursive:true so a permission error on ~/.ssh (HOME=/root for non-root user) is logged as a warning instead of crashing the server init --- back/loaders/initFile.ts | 6 +++++- docker/310.Dockerfile | 5 ++++- docker/Dockerfile | 5 ++++- docker/docker-entrypoint.sh | 11 ++++++++--- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/back/loaders/initFile.ts b/back/loaders/initFile.ts index 2eab9446..bc2133f7 100644 --- a/back/loaders/initFile.ts +++ b/back/loaders/initFile.ts @@ -104,7 +104,11 @@ const files = [ export default async () => { for (const dirPath of directories) { if (!(await fileExist(dirPath))) { - await fs.mkdir(dirPath); + try { + await fs.mkdir(dirPath, { recursive: true }); + } catch (err: any) { + Logger.warn(`Unable to create directory ${dirPath}: ${err.message}`); + } } } diff --git a/docker/310.Dockerfile b/docker/310.Dockerfile index fb690b57..d4abb308 100644 --- a/docker/310.Dockerfile +++ b/docker/310.Dockerfile @@ -65,11 +65,14 @@ RUN git clone --depth=1 -b ${QL_BRANCH} ${QL_URL} ${QL_DIR} \ && git clone --depth=1 -b ${QL_BRANCH} https://github.com/${QL_MAINTAINER}/qinglong-static.git /static \ && mkdir -p ${QL_DIR}/static \ && cp -rf /static/* ${QL_DIR}/static \ - && rm -rf /static + && rm -rf /static \ + && mkdir -p ${QL_DIR}/.tmp ${QL_DIR}/shell/preload \ + && chmod -R a+w ${QL_DIR}/.tmp ${QL_DIR}/shell/preload ${QL_DIR}/static ENV PNPM_HOME=${QL_DIR}/data/dep_cache/node \ PYTHON_HOME=${QL_DIR}/data/dep_cache/python3 \ PYTHONUSERBASE=${QL_DIR}/data/dep_cache/python3 \ + PM2_HOME=${QL_DIR}/data/.pm2 \ HOME=/root ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${PNPM_HOME}:${PYTHON_HOME}/bin:${HOME}/bin \ diff --git a/docker/Dockerfile b/docker/Dockerfile index 5682ae9d..eab7dac4 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -65,11 +65,14 @@ RUN git clone --depth=1 -b ${QL_BRANCH} ${QL_URL} ${QL_DIR} \ && git clone --depth=1 -b ${QL_BRANCH} https://github.com/${QL_MAINTAINER}/qinglong-static.git /static \ && mkdir -p ${QL_DIR}/static \ && cp -rf /static/* ${QL_DIR}/static \ - && rm -rf /static + && rm -rf /static \ + && mkdir -p ${QL_DIR}/.tmp ${QL_DIR}/shell/preload \ + && chmod -R a+w ${QL_DIR}/.tmp ${QL_DIR}/shell/preload ${QL_DIR}/static ENV PNPM_HOME=${QL_DIR}/data/dep_cache/node \ PYTHON_HOME=${QL_DIR}/data/dep_cache/python3 \ PYTHONUSERBASE=${QL_DIR}/data/dep_cache/python3 \ + PM2_HOME=${QL_DIR}/data/.pm2 \ HOME=/root ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${PNPM_HOME}:${PYTHON_HOME}/bin:${HOME}/bin \ diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh index 5d784cc3..b561febc 100755 --- a/docker/docker-entrypoint.sh +++ b/docker/docker-entrypoint.sh @@ -15,10 +15,10 @@ log_with_style() { printf "\n[%s] [%7s] %s\n" "${timestamp}" "${level}" "${message}" } -# Fix DNS resolution issues in Alpine Linux +# Fix DNS resolution issues in Alpine Linux (requires root) # Alpine uses musl libc which has known DNS resolver issues with certain domains # Adding ndots:0 prevents unnecessary search domain appending -if [ -f /etc/alpine-release ]; then +if [ "$(id -u)" = "0" ] && [ -f /etc/alpine-release ]; then if ! grep -q "^options ndots:0" /etc/resolv.conf 2>/dev/null; then echo "options ndots:0" >> /etc/resolv.conf log_with_style "INFO" "🔧 0. 已配置 DNS 解析优化 (ndots:0)" @@ -50,6 +50,11 @@ fi log_with_style "SUCCESS" "🎉 容器启动成功!" -crond -f >/dev/null +if [ "$(id -u)" = "0" ]; then + crond -f >/dev/null +else + # crond requires root in Alpine; keep container alive without it + exec tail -f /dev/null +fi exec "$@"