Ajenti Docker Compose 部署指南

Ajenti 2.2.18 官方无容器镜像的 Docker Compose 自建部署全记录:python:3.11-bookworm 基底加官方 21 插件 pip 清单、entrypoint 首启初始化与自签证书、8129 端口发布、命名卷配置持久化、down/up 数据保留验证与 pip 限速排障实录(Ubuntu 22.04 + Docker 29.9.2 实测,2026-11-02)。

Ajenti面板PythonDocker自托管服务器管理2026/11/02

Ajenti Docker Compose 部署指南

目标:在一台 Ubuntu 22.04 服务器上,用 Docker Compose 从零构建并部署 Ajenti 2.2.18 管理面板(官方无容器镜像,本篇给出完整自建方案),完成 HTTPS 访问、root 登录、配置与日志持久化、down/up 数据保留与反代路径等全链路实测。已在 Ubuntu 22.04(x86_64)+ Docker Engine 29.9.2 + Compose v5.6.1 实测通过。

Ajenti 是 Linux & BSD 的模块化服务器管理面板(定位、架构与选型见《Ajenti 介绍与选型指南》)。它的官方安装形态是"主机 pip 安装 + systemd 托管",不提供官方 Docker 镜像,因此容器化部署的全部工作量在于:把官方文档的依赖清单与 pip 安装清单翻译成一个可复现的 Dockerfile。本篇即完成这件事,并把它固化为一条 docker compose up 命令。

一、环境信息

项目取值
服务器操作系统Ubuntu 22.04(x86_64)
Docker Engine / Compose29.9.2 / v5.6.1(docker compose 子命令)
Ajenti 版本ajenti-panel 2.2.18(PyPI 最新稳定版,2026-10-25 发布;GitHub Release 标签为 v2.2.15,pip 通道更新更快)
面板基础镜像python:3.11-bookworm(自建,Debian 12 底)
项目目录/opt/ajenti-2.2.18/(Dockerfile、entrypoint.sh、config.yml、docker-compose.yml、data/logs/)
Compose 项目名ajenti-2.2.18-stack
服务名 / 主机名ajenti / ajenti-demo
监听面板 HTTPS 8000(服务内)→ 宿主发布 8129
内部网络user-defined bridge ajenti-2218-stack_ajenti-net(compose 把项目名 ajenti-2.2.18-stack 归一化为资源前缀 ajenti-2218-stack_),网段 10.89.56.0/24,固定地址 10.89.56.10
配置持久化命名卷 ajenti-2218-stack_ajenti-config → 服务内 /etc/ajenti
日志持久化宿主 bind /opt/ajenti-2.2.18/data/logs → 服务内 /var/log/ajenti
演示账号root / q1w2e3r4(os 认证,即系统口令)

💡 说明:Ajenti 默认监听 8000 端口且默认启用 HTTPS(自签证书)。本方案把宿主端口显式规划为 8129,避开 8000 的常见冲突;服务内端口保持 8000 不动,与官方文档所有示例路径一致。

二、镜像选型说明

Ajenti 官方不发容器镜像(2026-11-02 实查:GitHub Releases 仅有源码包,PyPI 仅有 pip 包,Docker Hub 无 ajenti 官方组织)。因此镜像只能自建。自建方案里真正要选的是"基底 + 依赖来源":

选型项本方案取值理由
基底镜像python:3.11-bookworm官方支持 Debian 9+;bookworm(Debian 12)的 python3-apt、python3-augeas 等系统绑定包齐全,与官方 apt 依赖清单一一对应
Ajenti 本体pip 安装 ajenti-panel 2.2.18官方推荐的安装通道(docs install.rst),版本随 PyPI 滚动
插件集官方"全插件"清单 21 个 ajenti.plugin.*docs install.rst "With all plugins" 原文清单,覆盖终端/文件/cron/服务/软件包等全部功能域
系统绑定apt 安装 python3-apt、python3-augeas、python3-dbus + .pth 桥接packages/augeas/dbus 插件必须 import 发行版自带的系统绑定,pip 版 Python 默认看不到 dist-packages,需显式加路径

⚠️ 注意:基底不要选 python:3.11-slim 或滚动到 Debian 13(trixie)标签的变体——trixie 已移除 python3-apt 等 Python 3.11 时代的系统绑定包,apt 依赖层会直接失败。本系列实验早期在 slim/trixie 上实测撞墙后固定为 bookworm。

💡 技术拓展:面板类软件容器化的三条常见路线——

路线做法取舍
官方镜像直用docker run 官方发布镜像最省事,但 Ajenti 没有
自建 pip 镜像官方 pip 清单 + 系统依赖装入 Debian 基底(本方案)与官方文档同源、可复现、版本可控
社区第三方镜像Docker Hub 个人维护的 ajenti 镜像版本陈旧(多停留在 1.x/2.0 时代)、无人维护,不建议生产使用

本方案采用"自建 pip 镜像",因为它是唯一与官方安装文档保持依赖一致性的路线。

三、前置条件

  1. 服务器已安装 Docker Engine 与 Compose v2+ 插件:
docker --version && docker compose version

回显(实测):

Docker version 29.9.2, build a82e528
Docker Compose version v5.6.1
  1. 宿主 8129 端口空闲:
ss -ltn | grep ':8129 ' || echo "8129 free"
  1. 服务器可直连 PyPI 与 deb.debian.org(构建期下载依赖;无法直连的环境见 4.6 节代理构建参数与 11.1 排障实录);
  2. 磁盘余量 ≥ 2GB(构建后镜像实测大小见 4.6 节回显)。

四、部署步骤

4.1 建立项目目录

所有部署文件集中在一个目录,compose 的相对路径构建上下文与 bind 挂载都以它为根:

mkdir -p /opt/ajenti-2.2.18/data/logs
cd /opt/ajenti-2.2.18

目录规划:

/opt/ajenti-2.2.18/
├── docker-compose.yml   # 编排:构建、端口、网络、持久化
├── Dockerfile           # 自建面板镜像定义
├── entrypoint.sh        # 首启初始化(配置落盘 + 自签证书)+ 前台启动
├── config.yml           # 默认主配置(构建时打进镜像,首启复制到持久卷)
└── data/logs/           # 宿主侧日志目录(bind 进 /var/log/ajenti)

4.2 编写 Dockerfile

/opt/ajenti-2.2.18/Dockerfile 全文如下(每段对应官方文档的一个安装步骤):

FROM python:3.11-bookworm

ENV DEBIAN_FRONTEND=noninteractive

# 官方 Debian/Ubuntu 依赖清单 + 运行时工具(对应 docs install.rst 手动安装一节)
RUN apt-get update && apt-get install -y --no-install-recommends \
        build-essential libssl-dev libffi-dev \
        libaugeas0 augeas-tools python3-augeas \
        python3-apt python3-dbus \
        dbus sudo vim-tiny nano procps iproute2 net-tools \
        curl git ca-certificates less cron ntpdate \
    && rm -rf /var/lib/apt/lists/*

# 让 pip 版 python 能 import apt/apt_pkg/augeas(Debian 系统包位于 dist-packages)
RUN echo '/usr/lib/python3/dist-packages' > /usr/local/lib/python3.11/site-packages/dist-packages.pth

# 可选构建参数:内网/慢链环境构建时传 --build-arg PIP_PROXY=http://<proxy>:<port>
ARG PIP_PROXY=""
# 可选构建参数:国内环境传 --build-arg PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple
ARG PIP_INDEX_URL=""

RUN pip install --no-cache-dir ${PIP_PROXY:+--proxy ${PIP_PROXY}} ${PIP_INDEX_URL:+-i ${PIP_INDEX_URL}} setuptools pip wheel -U

# 官方"全插件"安装清单(docs install.rst)
RUN pip install --no-cache-dir ${PIP_PROXY:+--proxy ${PIP_PROXY}} ${PIP_INDEX_URL:+-i ${PIP_INDEX_URL}} \
        ajenti-panel \
        ajenti.plugin.ace \
        ajenti.plugin.augeas \
        ajenti.plugin.auth-users \
        ajenti.plugin.core \
        ajenti.plugin.dashboard \
        ajenti.plugin.datetime \
        ajenti.plugin.filemanager \
        ajenti.plugin.filesystem \
        ajenti.plugin.network \
        ajenti.plugin.notepad \
        ajenti.plugin.packages \
        ajenti.plugin.passwd \
        ajenti.plugin.plugins \
        ajenti.plugin.power \
        ajenti.plugin.services \
        ajenti.plugin.settings \
        ajenti.plugin.terminal \
        ajenti.plugin.cron \
        ajenti.plugin.supervisor \
        ajenti.plugin.session-list

# 演示账号口令(os 认证走系统口令)
RUN echo 'root:q1w2e3r4' | chpasswd

COPY config.yml /opt/ajenti-default-config.yml
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh

EXPOSE 8000
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]

逐段说明:

  • apt 依赖层:build-essential/libssl-dev/libffi-dev 编译 cryptography、lxml 等 sdist 依赖;augeas-tools/libaugeas0/python3-augeas 支撑 augeas 插件;python3-apt 支撑 packages 插件;sudo 支撑 auth.allow_sudo 提权模型;vim-tiny/nano/procps/iproute2 让面板内的终端、文件编辑、服务管理开箱可用。
  • .pth 桥接:pip 安装的 Python 3.11 与发行版系统 Python 的包目录(/usr/lib/python3/dist-packages)互不可见,写入 .pth 文件后 import apt_pkg、import augeas 才能成功——这是 Ajenti 容器化最容易踩的坑(见 11.3 节)。
  • ARG PIP_PROXY / ARG PIP_INDEX_URL:两个可选构建参数默认空串不启用;${VAR:+--flag ${VAR}} 写法保证仅在传参时拼出对应 pip 选项,镜像内不留任何代理/源残留。国内网络构建强烈建议传清华源(见 4.6 与 11.1)。
  • chpasswd:Ajenti 默认认证 provider 是 os(直接校验系统口令),演示环境把 root 口令设为 q1w2e3r4。生产环境应改为 provider: users 自建账号体系(详见配置篇)。

4.3 编写 entrypoint.sh

服务进程需要一个"首启初始化 + 前台常驻"的入口,/opt/ajenti-2.2.18/entrypoint.sh:

#!/bin/bash
set -e
mkdir -p /etc/ajenti /var/log/ajenti
if [ ! -f /etc/ajenti/config.yml ]; then
    cp /opt/ajenti-default-config.yml /etc/ajenti/config.yml
    echo "[entrypoint] initial config.yml created"
fi
if [ ! -f /etc/ajenti/ajenti.pem ]; then
    ajenti-ssl-gen "$(hostname)"
    echo "[entrypoint] self-signed certificate generated"
fi
exec ajenti-panel -c /etc/ajenti/config.yml
  • 首启把镜像内置默认配置复制进持久卷 /etc/ajenti,此后卷内文件优先,升级重建镜像不会覆盖你改过的配置;
  • 首启用官方工具 ajenti-ssl-gen 以主机名签一张自签证书 /etc/ajenti/ajenti.pem(对应官方文档"缺证书就登录空白页"的补救命令);
  • exec ajenti-panel -c ... 让面板进程作为 1 号进程前台运行,docker stop 能把 SIGTERM 正确传给它。

4.4 默认主配置 config.yml

/opt/ajenti-2.2.18/config.yml——这份文件会被打进镜像作为"出厂配置",完整参数含义见 《Ajenti 2.2.18 配置参数详解》:

auth:
  allow_sudo: true
  emails: {}
  provider: os
  users_file: /etc/ajenti/users.yml
bind:
  host: 0.0.0.0
  mode: tcp
  port: 8000
color: bluegrey
language: en
max_sessions: 9
session_max_time: 3600
trusted_domains: []
trusted_proxies: []
name: Ajenti Demo Server
restricted_user: nobody
ssl:
  certificate: ''
  client_auth:
    certificates: []
    enable: false
    force: false
  enable: true
  force: false
  fqdn_certificate: ''
email:
  enable: false
  smtp:
    password: ''
    port: ''
    server: ''
    user: ''

要点:bind.host: 0.0.0.0 + bind.port: 8000(服务内监听)、ssl.enable: true(HTTPS)、auth.provider: os(系统账号登录)、language: en(官方仓库默认值是 ru,部署时必须显式改掉)。

💡 说明:出厂 ssl.certificate: '' 故意留空——首启由 ajenti-ssl-gen 生成自签证书后把路径回写进卷内配置(见 4.8 节日志的 config.yml updated with certificate path! 行)。各参数逐项含义见配置篇。

4.5 编写 docker-compose.yml

/opt/ajenti-2.2.18/docker-compose.yml 全文:

name: ajenti-2.2.18-stack

services:
  ajenti:
    build: .
    image: ajenti-2.2.18-panel:local
    container_name: ajenti-2.2.18-panel
    hostname: ajenti-demo
    ports:
      - "8129:8000"
    volumes:
      - ajenti-config:/etc/ajenti
      - /opt/ajenti-2.2.18/data/logs:/var/log/ajenti
    networks:
      ajenti-net:
        ipv4_address: 10.89.56.10
    restart: unless-stopped

networks:
  ajenti-net:
    driver: bridge
    ipam:
      config:
        - subnet: 10.89.56.0/24

volumes:
  ajenti-config:

字段解读:

字段取值作用
nameajenti-2.2.18-stack显式项目名,down 只影响本组件资源
build / image. / ajenti-2.2.18-panel:local本地构建并固定标签,便于 docker run 等价复现
container_nameajenti-2.2.18-panel固定名,便于 exec/logs
hostnameajenti-demo首启 ajenti-ssl-gen $(hostname) 的证书 CN
ports8129:8000宿主 8129 → 服务内 8000
volumes命名卷 + bind/etc/ajenti 配置持久化;data/logs 日志落宿主
networks10.89.56.0/24,固定 IP显式网段规划,避免与既有网络冲突
restartunless-stopped宿主机重启后面板自动拉起

4.6 构建镜像

cd /opt/ajenti-2.2.18
docker compose build --build-arg PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple

构建输出节选(实测首尾):

 Image ajenti-2.2.18-panel:local Building 
#1 [internal] load local bake definitions
#1 reading from stdin 602B done
#1 DONE 0.0s

#2 [internal] load build definition from Dockerfile
#2 transferring dockerfile: 2.24kB done
#2 DONE 0.0s

#3 [internal] load metadata for docker.io/library/python:3.11-bookworm
#3 DONE 0.2s
...
#15 DONE 18.2s

#16 resolving provenance for metadata file
#16 DONE 0.0s
 Image ajenti-2.2.18-panel:local Built 

构建完成后核对产物:

docker images ajenti-2.2.18-panel
IMAGE                       ID             DISK USAGE   CONTENT SIZE   EXTRA
ajenti-2.2.18-panel:local   dcc98dd37504       1.87GB          457MB   U

(Docker 29 的 docker images 以 DISK USAGE/CONTENT SIZE 两列展示共享与独占占用;本镜像独占层 457MB、含共享层总占用 1.87GB,与"磁盘余量 ≥ 2GB"的前置要求吻合。)

⚠️ 注意:ajenti.plugin.* 系列在 PyPI 上只发 sdist(源码包),21 个插件 + 依赖全部要现场解包构建 wheel,正常耗时 10–20 分钟;若中途超时按 11.1 节处理。

4.7 启动服务栈

docker compose up -d

回显(实测):

 Network ajenti-2218-stack_ajenti-net Creating 
 Volume ajenti-2218-stack_ajenti-config Creating 
 Volume ajenti-2218-stack_ajenti-config Creating 
 Network ajenti-2218-stack_ajenti-net Creating 
 Volume ajenti-2218-stack_ajenti-config Created 
 Volume ajenti-2218-stack_ajenti-config Created 
 Network ajenti-2218-stack_ajenti-net Created 
 Network ajenti-2218-stack_ajenti-net Created 
 Container ajenti-2.2.18-panel Creating 
 Container ajenti-2.2.18-panel Created 
 Container ajenti-2.2.18-panel Starting 
 Container ajenti-2.2.18-panel Started 

查看运行状态与端口发布:

docker compose ps
NAME                  IMAGE                       COMMAND                  SERVICE   CREATED                  STATUS                  PORTS
ajenti-2.2.18-panel   ajenti-2.2.18-panel:local   "/usr/local/bin/entr…"   ajenti    Less than a second ago   Up Less than a second   0.0.0.0:8129->8000/tcp, [::]:8129->8000/tcp

4.8 验证启动日志

docker compose logs ajenti

回显(实测):

[entrypoint] initial config.yml created
:: Certificate /etc/ajenti/ajenti.pem generated!
:: /etc/ajenti/config.yml updated with certificate path!
[entrypoint] self-signed certificate generated

(ajenti-ssl-gen 执行时伴随大量 pyOpenSSL DeprecationWarning 行,属预期噪音,已滤除;成功标志即上面两条 :: 行。)

面板进程自身的日志不写 stdout 而是落 /var/log/ajenti/ajenti.log(宿主 bind 目录 data/logs/),首启就绪序列(实测节选):

2026-11-02 14:57:45,077 INFO    : Ajenti Core 2.2.18
2026-11-02 14:57:45,077 INFO    : Master PID - 1
2026-11-02 14:57:45,077 INFO    : Detected platform: debian / Linux 7.0.0-38-generic x86_64
2026-11-02 14:57:45,077 INFO    : Python version: 3.11.18
2026-11-02 14:57:45,092 INFO    : Discovered 20 plugins
2026-11-02 14:57:45,097 WARNING : Not loading [supervisor] because dependency failed: BinaryDependency (supervisorctl)
2026-11-02 14:57:45,166 INFO    : Loaded 19 plugins
2026-11-02 14:57:45,166 INFO    : Binding to [0.0.0.0]:8000
2026-11-02 14:57:45,170 INFO    : No secret found, generating new secret key
2026-11-02 14:57:45,174 INFO    : SSL enabled

Binding to [0.0.0.0]:8000 + SSL enabled 为面板主进程就绪标志;Not loading [supervisor] 一条 WARNING 属预期——镜像未装 supervisorctl,需要管理 supervisor 服务时再补装。

4.9 验证 HTTPS 访问与登录

curl -kIs https://localhost:8129/ | head -8
HTTP/1.1 302 Found
X-Auth-Identity: 
Location: /view/login/normal
X-Worker-Name: restricted session
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self';
Date: Mon, 02 Nov 2026 14:58:17 GMT
Content-Length: 0

未登录访问根路径即 302 跳转登录页;登录页本体 curl -ks -o /dev/null -w '%{http_code}\n' https://localhost:8129/view/login/normal 返回 200。

登录接口实测(os 认证,root / q1w2e3r4):

curl -ks -c /tmp/ajcjB -o /tmp/ajbodyB -X POST https://localhost:8129/api/core/auth \
  -H 'Content-Type: application/json' \
  -d '{"mode":"normal","username":"root","password":"q1w2e3r4"}'
cat /tmp/ajbodyB

curl -ks -X POST https://localhost:8129/api/core/auth \
  -H 'Content-Type: application/json' \
  -d '{"mode":"normal","username":"root","password":"bad"}'

curl -kb /tmp/ajcjB -s https://localhost:8129/api/core/identity
{"success": true, "username": "root"}
{"success": false, "error": null}
{"identity": {"user": "root", "uid": 0, "effective": 0, "elevation_allowed": true, "profile": {}}, "machine": {"name": "Ajenti Demo Server", "hostname": "ajenti-demo"}, "color": "bluegrey"}

正确口令返回 success: true 并下发会话 Cookie;错误口令返回 success: false;带 Cookie 调 /api/core/identity 确认登录态与面板标题。

浏览器访问 https://<服务器IP>:8129,信任自签证书后用 root / q1w2e3r4 登录,即可看到 Dashboard/配置/终端/软件包等页面。

五、数据持久化说明

服务内路径内容持久化方式宿主/卷位置
/etc/ajenti/config.yml主配置命名卷 ajenti-2218-stack_ajenti-config卷内
/etc/ajenti/users.ymlprovider: users 时的面板用户库同上卷内
/etc/ajenti/ajenti.pem自签 HTTPS 证书同上卷内
/etc/ajenti/smtp.yml邮件中继凭据(找回密码用)同上卷内
/var/log/ajenti/ajenti.log运行日志与失败登录记录bind/opt/ajenti-2.2.18/data/logs/
/var/log/ajenti/crash-*.txt崩溃栈(实测命名 crash-<日期>-<时刻>h<分>.txt,官方文档写 crash-DATE.log,以代码为准)bind同上

持久化验证——重建栈后配置不丢:

docker compose down
docker compose up -d
grep -c 'initial config.yml created' data/logs/ajenti.log   # 首启标记不新增 = 卷内配置未重初始化
curl -k -s -o /dev/null -w '%{http_code}\n' https://localhost:8129/
 Container ajenti-2.2.18-panel Removing 
 Container ajenti-2.2.18-panel Removed 
 Network ajenti-2218-stack_ajenti-net Removing 
 Network ajenti-2218-stack_ajenti-net Removed 
 Container ajenti-2.2.18-panel Created 
 Container ajenti-2.2.18-panel Starting 
 Container ajenti-2.2.18-panel Started 
0
after up: 302

down 不带 -v 时命名卷保留,重建容器后首启初始化标记不再新增(计数 0),配置、证书、会话密钥全部原样恢复。

💡 说明:Ajenti 无内置数据库,全部状态就是这几个 YAML/PEM 文件;备份 /etc/ajenti 卷即备份整个面板配置。导出方法见第十章。

六、环境变量与构建参数说明

Ajenti 面板进程不读取环境变量,配置唯一来源是 /etc/ajenti/config.yml(这是它与 1Panel 等"环境变量驱动"面板的关键差异)。本镜像涉及的环境变量/构建参数只有:

名称位置默认值说明
DEBIAN_FRONTEND构建期 ENVnoninteractive仅 apt 无人值守用
PIP_PROXY构建 ARG空(不启用)--build-arg PIP_PROXY=http://<proxy>:<port> 时为 pip 指定代理,不进镜像
PIP_INDEX_URL构建 ARG空(官方源)--build-arg PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple 换国内源,不进镜像
TZ可选 ENVUTC容器时区;面板 datetime 插件读写的是系统时区,建议宿主与容器一致

💡 技术拓展:容器化应用的配置注入两条主流路线——

路线代表特点
环境变量驱动imgproxy、多数 Go 服务十二要素、compose environment: 即可改
配置文件挂载Ajenti、多数传统 Linux 服务需挂载配置目录 + 首启初始化(本方案的 entrypoint/volume 设计即为此)

Ajenti 属于后者,所以本方案用"镜像带出厂配置 + 命名卷存运行配置"的组合,而不是 env 覆盖。

七、配置参数说明(速览)

出厂 config.yml 各块含义速览(逐项详解、修改方法与生效验证见 《Ajenti 2.2.18 配置参数详解》):

块/键本方案取值一句话含义
auth.provideros登录账号来源:系统账号(另一选项 users 面板自管)
auth.allow_sudotrue允许 sudo 组成员在面板内提权
bind.host/port0.0.0.0:8000监听地址与端口
ssl.enabletrueHTTPS(证书 /etc/ajenti/ajenti.pem)
session_max_time3600会话有效期(秒)
max_sessions9同时在线会话上限
languageen界面语言(官方默认 ru,必须显式改)
restricted_usernobody受限操作降权用户

八、配置文件挂载方式

运行期配置在命名卷内,修改走"进服务改文件 + 重启进程":

docker compose exec ajenti sed -i 's/^name: Ajenti Demo Server/name: Ajenti Ops Demo/' /etc/ajenti/config.yml
docker compose restart
curl -ks -c /tmp/rj -X POST https://localhost:8129/api/core/auth -H 'Content-Type: application/json' -d '{"mode":"normal","username":"root","password":"q1w2e3r4"}'
curl -kb /tmp/rj -s https://localhost:8129/api/core/identity
{"identity": {"user": "root", "uid": 0, "effective": 0, "elevation_allowed": true, "profile": {}}, "machine": {"name": "Ajenti Ops Demo", "hostname": "ajenti-demo"}, "color": "bluegrey"}

改回原值并重启即恢复稳态。面板 Settings 页改标题/主题色等参数写回的是同一个文件,效果相同(参数逐项详解见配置篇)。

entrypoint 只在 /etc/ajenti/config.yml 不存在时才复制出厂配置,因此卷内文件永远优先,升级镜像不会覆盖修改。

若更希望"配置即代码"(宿主 git 管理),可把主配置改为 bind 单文件挂载:

# docker-compose.yml volumes 段的替代写法(二选一)
volumes:
  - ajenti-config:/etc/ajenti
  - ./config.yml:/etc/ajenti/config.yml:ro   # 宿主文件直接接管主配置

⚠️ 注意:单文件 bind 后 config.yml 变只读,面板内 Settings 页保存会失败(写入方是进程本身);需要面板内改配置时去掉 :ro 或回到命名卷方案。

九、等价 docker run

compose 的运行时等价命令(同镜像、同持久化语义,仅网络用默认 bridge 演示):

docker run -d --name ajenti-run-demo -p 8131:8000 ajenti-2.2.18-panel:local
e9e5944c1d3907b23b9f446ddf8709b4be83d7efb305f2e05228552bbcb2923e
run-demo 8131: 302
[entrypoint] initial config.yml created
:: Certificate /etc/ajenti/ajenti.pem generated!
:: /etc/ajenti/config.yml updated with certificate path!
[entrypoint] self-signed certificate generated

(run-demo 8131: 302 为 curl -k -s -o /dev/null -w '%{http_code}' https://localhost:8131/ 的实测输出;其余为 docker logs ajenti-run-demo 节选。)

验证完毕销毁该演示实例:

docker rm -f ajenti-run-demo
ajenti-run-demo

十、常用运维命令

操作命令
状态docker compose ps
跟踪日志docker compose logs -f ajenti
重启面板docker compose restart
进入服务docker compose exec ajenti bash
停止并删除栈(保留数据卷)docker compose down
连数据一起销毁docker compose down -v
改 Dockerfile 后重建并拉起docker compose up -d --build
导出配置备份docker run --rm -v ajenti-2218-stack_ajenti-config:/etc/ajenti -v "$(pwd)":/backup alpine tar czf /backup/ajenti-etc.tar.gz /etc/ajenti

实测节选(配置备份导出):

docker run --rm -v ajenti-2218-stack_ajenti-config:/etc/ajenti -v "$(pwd)":/backup alpine \
  tar czf /backup/ajenti-etc.tar.gz /etc/ajenti
ls -la ajenti-etc.tar.gz
tar: removing leading '/' from member names
-rw-r--r-- 1 root root 4466 Nov  2 23:01 ajenti-etc.tar.gz

全部配置状态仅 4.4KB(五个 YAML/PEM 文件),还原时把 tar 解回同名卷即可。其余命令回显见 4.7(ps)、五章(down/up)、八章(exec/restart)实测节。

十一、常见问题

11.1 构建期 pip 下载超时/卡死

现象:docker compose build 停在 Downloading ajenti_plugin_core-0.117.tar.gz (17.5 MB) 长时间不动(本篇实验实测在该处卡死 5 分钟以上无字节流动),或最终报 ConnectTimeoutError。

定位:小体积包(几 MB)能过、大包卡死,多为到 files.pythonhosted.org 的链路被限速。本篇实测对照:同一台服务器直连官方源下载该 17.5MB 包仅 302KB/s(20 秒超时窗口只完成 4.5MB),而清华镜像源同包 20.9MB/s 整包秒下:

URL=https://files.pythonhosted.org/packages/30/99/b5af989e33a2f1082a5e7c6dede275aedff351d3871af0167c1d724d8d12/ajenti_plugin_core-0.117.tar.gz
timeout 20 curl -s -o /dev/null -w "official=%{speed_download} B/s size=%{size_download}\n" "$URL"
timeout 20 curl -s -o /dev/null -w "tuna=%{speed_download} B/s size=%{size_download}\n" \
  "https://pypi.tuna.tsinghua.edu.cn/packages/30/99/b5af989e33a2f1082a5e7c6dede275aedff351d3871af0167c1d724d8d12/ajenti_plugin_core-0.117.tar.gz"
official=302132 B/s size=4532101
tuna=20883032 B/s size=17513806

解决:构建时传入国内源参数(Dockerfile 已内置支持):

docker compose build --build-arg PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple

海外/有代理环境则传 --build-arg PIP_PROXY=http://<proxy>:<port>,两者可同用。

11.2 登录后页面空白

官方文档已知问题:gipc/gevent 版本过旧导致。容器方案按 2.2.18 全新安装不受影响(实测版本核对):

docker compose exec ajenti pip3 show gipc gevent | grep -E '^(Name|Version)'
Name: gipc
Version: 1.8.0
Name: gevent
Version: 25.5.1

若你手动改过依赖导致回落旧版,按官方补救命令升级:pip install gipc gevent -U。

11.3 packages/augeas 插件报 ModuleNotFoundError: No module named 'apt_pkg'

原因:pip 版 Python 看不到 Debian 系统绑定目录。解决:确认 Dockerfile 的 .pth 桥接层存在(4.2 节),验证:

docker compose exec ajenti python3 -c "import apt_pkg, augeas; print('apt_pkg/augeas import ok')"
apt_pkg/augeas import ok

11.4 浏览器证书告警

自签证书属预期行为。生产建议:前置反代挂正式证书(配合 trusted_domains/trusted_proxies/url_prefix,见配置篇),或用 ajenti-client-ssl-gen 走客户端证书方案。

十二、参考链接

Ajenti Docker Compose 部署指南 - Quzuo