Misago 0.39.6 Docker Compose 部署指南

用官方 misago_docker 部署包以 Docker Compose 从零构建上线 Misago 0.39.6 五服务栈:非交互初始化、环境变量表、数据持久化、等价 docker run,完整沉淀端口占用、证书隔离与 celery 混入 upstream 排障实录。

MisagoMisagoDockerDocker ComposePostgreSQLRedis2026/11/02

Misago 0.39.6 Docker Compose 部署指南

目标:用官方部署包 rafalp/misago_docker(Misago 0.39.6)以 Docker Compose 方式从零部署一套自托管 Misago 论坛:本地构建应用与代理镜像、非交互初始化数据库与管理员、五服务(misago / celery-worker / nginx-proxy / postgres-15 / redis-6)编排上线,并完整沉淀端口占用、证书服务隔离、celery 混入 upstream 等排障实录。已在 Ubuntu 24.04.5 LTS + Docker 29.9.2 + Compose v5.6.1 环境全量实测通过,文中所有命令与回显均为实测原文。

一、环境信息

本文所有命令与输出均在以下环境实测采集:

  • 操作系统:Ubuntu 24.04.5 LTS(x86_64,kernel 7.0.0-38)
  • Docker:29.9.2(含 Docker Compose v5.6.1 插件)
  • Misago:0.39.6(部署包 HEAD 275343f Update to Misago 0.39.6,2026-06-19;requirements.in 钉住 misago==0.39.6)
  • 应用运行时:Python 3.12(基础镜像 python:3.12-bookworm)+ Django 4.2.8 + uWSGI(socket :3031,uwsgi 协议,4 worker)
  • 数据库:PostgreSQL 15.19(官方镜像 postgres:15)
  • 缓存/队列:Redis 6(官方镜像 redis:6;DB1 缓存与会话、DB0 Celery 队列)
  • 反向代理:nginx-proxy(部署包本地构建,基于 jwilder/nginx-proxy 体系,实测 nginx 1.31.6)+ letsencrypt companion(jrcs/letsencrypt-nginx-proxy-companion:2.2)
  • 部署目录:/opt/misago(本文示例路径,即 git clone 目标)
  • 站点地址:http://192.168.1.172:8128/(场景:宿主 80/443 已被既有服务占用,故以 IP 绑定 + 8128 端口发布;HTTPS/letsencrypt 经 profiles 隔离未启用,见 4.3 与 FAQ 11.1)
  • 管理员账号:admin / q1w2e3r4(演示口令)
  • 数据库账号:库/用户/口令 misagodb / misagodb / misagodbpassword(compose 默认值)
  • 五服务常驻内存实测(完成初始化与 50 次请求压测后采样,docker stats --no-stream):
服务内存占用说明
misago139.4 MiBuWSGI 主应用(4 worker)
celery-worker355.3 MiBCelery worker(与主应用同镜像)
nginx-proxy42.1 MiB反向代理
postgres-1521.4 MiB空库 + 少量测试数据
redis-62.9 MiB缓存 + 队列
合计约 561 MiB官方 README 标注 1GB 内存起步,吻合

二、镜像选型说明

官方不发布预构建应用镜像——实查 Docker Hub:misago 命名空间 2018 年注册但公开仓库数为 0,不存在 misago/misago 镜像。官方部署路径就是 rafalp/misago_docker 部署包:应用与代理两个镜像在本地 docker compose build 构建,数据库与缓存直接复用官方镜像(与部署包 docker-compose.yaml 固定写法一致):

镜像来源本实测 tag体积(实测)用途
misago_docker-misago本地构建(misago/Dockerfile)latest2.13GB(内容 551MB)uWSGI 主应用
misago_docker-celery-worker本地构建(同一 Dockerfile)latest同上(层共享)Celery worker
misago_docker-nginx-proxy本地构建(nginx-proxy/ 目录)latest271MB(内容 74.6MB)反向代理(docker-gen 动态配置)
postgres:15Docker Hub 官方15.19—主存储 + 全文检索
redis:6Docker Hub 官方6.x—缓存/会话 + 队列
jrcs/letsencrypt-nginx-proxy-companion:2.2Docker Hub2.2—自动签发 TLS(本实测未启用)

版本锁定机制:应用版本由部署包仓库的 misago/requirements.in 钉住(当前 misago==0.39.6),没有可选的镜像 tag——升级 = 更新部署包(./appctl upgrade 走 git pull + rebuild),而非改 tag。

💡 技术拓展:论坛类软件的容器交付物形态主要有三类,对比——

形态代表特点取舍
官方预构建镜像 + 版本 tagMastodon、Grafana拉取即用,升级改 tag供应链信任镜像仓库
官方部署包本地构建Misago(misago_docker)版本由 requirements 钉死,构建产物自主可控首次构建耗时、需构建环境
无官方容器化,社区 compose 文件phpBB灵活编排质量参差

Misago 属第二类:好处是应用与编排同仓库、同 commit 演进(appctl 工具链直接可依赖仓库结构),代价是首次部署要本地构建 2.13GB 镜像。

⚠️ 网络说明:本实测环境直连 hub.docker.com 被拒,postgres:15、redis:6、python:3.12-bookworm 等基础镜像经 docker daemon 的 registry-mirrors 加速拉取;GitHub 仓库直连可通。若你的服务器可直连 Docker Hub,无需任何额外配置。

三、前置条件

  1. Docker 与 Compose 插件:宿主机安装 Docker 24+ 与 docker compose v2+ 插件。验证:

    docker compose version
    

    实测回显:

    Docker Compose version v5.6.1
    
  2. 端口规划:基础编排默认发布 80:80、443:443。本实测宿主 80/443 已被既有服务占用,改走 192.168.1.172:8128 IP 绑定发布。确认目标端口空闲:

    ss -ltn | grep ':8128'
    

    实测回显(规划时无输出 = 端口空闲;后续被本栈占用后回显监听行):

    LISTEN 0 4096 192.168.1.172:8128 0.0.0.0:*
    
  3. 网段规划:编排使用自定义网络,多栈共存建议显式指定子网避免冲突。查看已占用网段:

    docker network ls && docker network inspect <已有栈网络> -f '{{range .IPAM.Config}}{{.Subnet}}{{end}}'
    

    本文实测选用空闲网段 10.89.56.0/24(见 4.3 override)。

  4. 资源:五服务常驻约 561MiB(第一章实测表)+ 构建期峰值,建议 ≥2GB 内存、预留 8GB 磁盘(构建镜像约 2.4GB + 数据目录)。

  5. 域名与邮件规划:生产站点需要域名(VIRTUAL_HOST/MISAGO_ADDRESS)与 SMTP 服务;本文用 IP + console 邮件演示,参数语义见第六章环境变量表。

四、部署步骤

官方标准路径是交互式向导 ./appctl setup(问答式生成配置并自动完成本章全部步骤)。本章给出非交互等价流程,适合自动化与排障理解;两种方式产物一致。

4.1 获取官方部署包

git clone https://github.com/rafalp/misago_docker.git /opt/misago
cd /opt/misago
git log -1 --format='%h %s (%ad)' --date=short

实测回显:

275343f Update to Misago 0.39.6 (2026-06-19)

部署包目录结构(实测):appctl(482 行主机侧工具链)、docker-compose.yaml(六服务基础编排)、misago/(应用镜像构建上下文,含 Dockerfile、uwsgi.ini、misagodocker/settings.py、cron 维护脚本、.run 容器内脚本)、nginx-proxy/(代理构建上下文)、wizard/(setup 等配置向导)、config/(misago.env 与 vhost.d)、backups/、logs/。

4.2 写应用环境文件 config/misago.env

config/misago.env 是应用与 celery-worker 共用的 env_file(./appctl setup 向导生成的就是这个文件)。非交互部署直接手写,实测最终内容(密钥以占位说明,生成方法见下):

# 先生成站点密钥(Django SECRET_KEY,一次性随机)
python3 -c "import secrets; print(secrets.token_urlsafe(32))"

生成命令实测回显(示例输出,实际值每次不同,填入 misago.env):

ZuWKW5tLxKpmaCJgurK88C_7aa7HcO5s4lVNA6fdRGA

config/misago.env 完整内容(本实测环境):

MISAGO_DEBUG=no
MISAGO_DAILY_BACKUP=yes
MISAGO_SECRET_KEY=<上面生成命令的输出>
MISAGO_ADDRESS=http://192.168.1.172:8128/
MISAGO_LANGUAGE_CODE=en-us
MISAGO_SEARCH_CONFIG=simple
MISAGO_TIME_ZONE=Asia/Shanghai
MISAGO_INDEX=categories
MISAGO_EMAIL_PROVIDER=console
MISAGO_DEFAULT_FROM_EMAIL=noreply@example.com

逐项含义:MISAGO_DEBUG 调试开关(no/yes,strtobool 解析);MISAGO_SECRET_KEY 会话/CSRF 签名密钥(泄露即可伪造会话,勿提交版本库);MISAGO_ADDRESS 站点地址(供 appctl 向导族与站内展示使用);MISAGO_LANGUAGE_CODE/MISAGO_TIME_ZONE 语言与时区;MISAGO_SEARCH_CONFIG PostgreSQL 全文检索配置;MISAGO_INDEX 首页形态(categories=版块索引 / threads=帖子列表);MISAGO_EMAIL_PROVIDER=console 邮件打到日志(生产换 smtp 分支,参数见配置篇)。各键的读取位置、默认值与生效机制详解见《Misago 0.39.6 配置参数详解》。

⚠️ 注意:不要把 VIRTUAL_HOST 写进这个文件——celery-worker 与 misago 共用该 env_file,VIRTUAL_HOST 会让 docker-gen 把 celery 也注册进 nginx upstream 造成 502 隐患,本实测踩坑与修复见 FAQ 11.3/11.5。VIRTUAL_HOST 只写在 misago 服务的 override environment 里(4.3)。

4.3 写端口与服务适配 docker-compose.override.yml

Compose 会自动合并同目录的 docker-compose.override.yml。本实测场景需要四处适配:80/443 被占改 8128 IP 绑定、不启用 letsencrypt companion、VIRTUAL_HOST 仅注入 misago、固定子网。完整文件(实测最终版):

services:
  nginx-proxy:
    ports: !override
      - "192.168.1.172:8128:80"

  nginx-lets-encrypt:
    profiles:
      - letsencrypt

  misago:
    environment:
      - VIRTUAL_HOST=192.168.1.172
    depends_on:
      nginx-lets-encrypt:
        required: false
      postgres-15:
        condition: service_started
      redis-6:
        condition: service_started

networks:
  misago:
    ipam:
      config:
        - subnet: 10.89.56.0/24

逐项说明:

  • ports: !override:compose 对 ports 列表的默认合并语义是追加而非替换,不加 !override 标签则最终会同时发布 80、443、8128 三个端口,与宿主占用冲突(排障实录见 FAQ 11.1);
  • profiles: [letsencrypt]:把证书签发服务移出默认启动集,IP+HTTP 场景不需要(也避免其依赖 docker.sock 签证书失败循环重启);
  • environment: VIRTUAL_HOST=192.168.1.172:nginx-proxy 靠容器的 VIRTUAL_HOST 环境变量生成 server_name/upstream,只给 misago 服务注入(11.3 坑);
  • depends_on 长格式 required: false:基础编排里 misago depends_on 列表含 nginx-lets-encrypt,且 depends_on 列表会被归一化为 map 合并、无法用 override 删项,必须用长格式把该依赖降级为 optional(排障见 FAQ 11.2);
  • ipam.subnet:显式固定 10.89.56.0/24,避免与宿主其他栈网段冲突。

验证合并结果(服务清单应只剩 5 个、端口只剩 8128):

docker compose config --services
docker compose config | grep -A6 '    ports:'

实测回显(nginx-lets-encrypt 已不在默认服务集;ports 只剩 8128 一条发布):

postgres-15
redis-6
celery-worker
misago
nginx-proxy
    ports:
      - mode: ingress
        host_ip: 192.168.1.172
        target: 80
        published: "8128"
        protocol: tcp

4.4 构建应用与代理镜像

cd /opt/misago
docker compose build

实测回显(buildkit 输出节选,实测首尾;完整构建约 10 分钟,大头是 pip 依赖与前端资产编译):

#24 [celery-worker] resolving provenance for metadata file
#24 DONE 0.0s
 Image misago_docker-nginx-proxy Built
 Image misago_docker-celery-worker Built
 Image misago_docker-misago Built

验证构建产物:

docker images | grep misago_docker

实测回显:

misago_docker-celery-worker:latest    96ee6839a33f    2.13GB    551MB
misago_docker-misago:latest           22a222a8e836    2.13GB    551MB
misago_docker-nginx-proxy:latest      34cd3a9ee5c6    271MB     74.6MB

misago 与 celery-worker 由同一 misago/Dockerfile 构建(层共享),仅启动命令不同:前者 uwsgi --ini uwsgi.ini,后者 celery -A misagodocker worker --loglevel=info。

4.5 初始化数据库与管理员

先起依赖服务,再逐步初始化(官方 ./appctl setup 内部即此序列):

docker compose up -d postgres-15 redis-6
docker compose run --rm misago python manage.py migrate

实测回显(稳态复跑形态;首次初始化时逐条输出 Applying 状态行,22 组迁移域全部通过):

  Apply all migrations: admin, auth, contenttypes, misago_acl, misago_cache, misago_categories, misago_conf, misago_core, misago_icons, misago_legal, misago_menus, misago_notifications, misago_oauth2, misago_readtracker, misago_socialauth, misago_themes, misago_threads, misago_users, sessions, social_django
Running migrations:
  No migrations to apply.
docker compose run --rm misago python manage.py loadavatargallery

实测回显:

New galleries have been loaded.
# 创建管理员(演示口令 q1w2e3r4)
docker compose run --rm misago python manage.py createsuperuser \
  --noinput --username admin --email admin@example.com --password q1w2e3r4

实测回显:

Superuser #1 has been created successfully.

⚠️ 注意:必须带 Misago 原生扩展的 --password 参数。Misago 自带(users 应用覆盖的)createsuperuser 不读 Django 惯例的 DJANGO_SUPERUSER_PASSWORD 环境变量,--noinput 缺密码时静默 exit 0 且不建用户——这是本实测踩坑之一,详见 FAQ 11.4。

验证管理员落库:

docker compose exec -T misago python manage.py shell -c \
  "from misago.users.models import User; u=User.objects.get(username='admin'); print(u.is_superuser)"

实测回显:

True
docker compose run --rm misago python manage.py collectstatic --no-input

实测回显:

348 static files copied to '/misago/static', 1 unmodified, 349 post-processed.

4.6 全量启动与上线验证

docker compose up -d
docker compose ps

实测回显(五服务全部 Up,仅 nginx-proxy 发布端口):

NAME                            IMAGE                                             COMMAND                  SERVICE         STATUS          PORTS
misago_docker-celery-worker-1   sha256:a79d72f0cf0538e508f51076f29e2d44e779d54b   "celery -A misagodoc…"   celery-worker   Up 18 minutes   3031/tcp
misago_docker-misago-1          sha256:a282a28d5caeda71c6b15b543f94b41f15c22691   "uwsgi --ini uwsgi.i…"   misago          Up 18 minutes   3031/tcp
misago_docker-nginx-proxy-1     misago_docker-nginx-proxy                         "/app/docker-entrypo…"   nginx-proxy     Up 19 minutes   192.168.1.172:8128->80/tcp
misago_docker-postgres-15-1     postgres:15                                       "docker-entrypoint.s…"   postgres-15     Up 19 minutes   5432/tcp
misago_docker-redis-6-1         redis:6                                           "docker-entrypoint.s…"   redis-6         Up 19 minutes   6379/tcp
curl -sI http://192.168.1.172:8128/ | head -4
curl -s http://192.168.1.172:8128/ | grep -oE '<title>[^<]*</title>'
curl -sI http://192.168.1.172:8128/admincp/ | head -2

实测回显:

HTTP/1.1 200 OK
Server: nginx/1.31.6
Date: Mon, 02 Nov 2026 07:21:10 GMT
Content-Type: text/html; charset=utf-8
<title>Misago</title>
HTTP/1.1 200 OK
Server: nginx/1.31.6

连续 50 次请求验证 upstream 稳定性(确认无 celery 混入导致的间歇 502,见 11.3):

for i in $(seq 1 50); do curl -s -o /dev/null -w '%{http_code} ' http://192.168.1.172:8128/; done; echo

实测回显:

200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200

检查应用与后台任务日志:

docker compose exec misago tail -2 /misago/logs/uwsgi.log
docker compose logs --tail 3 celery-worker

实测回显:

[pid: 8|app: 0|req: 2/7] 192.168.1.172 () {32 vars in 370 bytes} [Mon Nov  2 15:21:10 2026] HEAD /admincp/ => generated 2091 bytes in 22 msecs (HTTP/1.1 200) 10 headers in 504 bytes (1 switches on core 0)
celery-worker-1  | [2026-11-02 15:02:36,111: INFO/MainProcess] celery@8074ff718bdc ready.

浏览器访问 http://192.168.1.172:8128/ 可见版块索引首页(MISAGO_INDEX=categories),/admincp/ 用 admin / q1w2e3r4 登录管理后台。部署完成。

五、数据持久化说明

编排的数据落位 = named volume(数据库/证书)+ bind mount(应用资产,全部在部署目录内,随目录备份迁移):

数据落位路径/卷名实测占用说明
PostgreSQL 数据named volumemisago-postgres-15 → /var/lib/postgresql/data随数据增长帖子/用户/动态设置全在此
Redis 数据named volumemisago-redis-6 → /data2.9MiB缓存/会话/队列,可丢(丢=全员登出)
TLS 证书named volumenginx-certs、nginx-html、lets-encrypt-acme空(未启用证书)启用 letsencrypt 后落这里
用户上传媒体bind./misago/media → /misago/media2.7M头像、附件
静态资产bind./misago/static → /misago/static37Mcollectstatic 产物
头像库bind 只读./misago/avatargallery → /misago/avatargallery:ro2.3Mloadavatargallery 产物
主题覆盖bind 只读./misago/theme → /misago/theme:ro20K自定义模板/静态覆盖点
备份归档bind./backups → /misago/backups2.2M/份appctl backup 产物
应用日志bind./logs → /misago/logs(nginx 日志在 ./logs/nginx)216Kmisago.log/celery.log/uwsgi.log,周轮转,60 天清理
nginx 站点片段bind./config/vhost.d → /etc/nginx/vhost.d12K按域名注入代理片段

备份归档结构实测(./appctl backup 产物,tar 内含数据库 SQL 与全量 media):

tar -tzf backups/manual-20261102152126.tar.gz | head -4

实测回显:

manual-20261102152126/
manual-20261102152126/media/
manual-20261102152126/media/avatars/
manual-20261102152126/database.sql

⚠️ 注意:docker compose down -v 会删除 named volumes(数据库数据全丢),bind mount 目录则保留在部署目录内。卸载前务必先 ./appctl backup;日常恢复演练见命令篇 restore 一节。

六、环境变量表

Misago 部署包的变量分三层,逐层列全(读取位置均实测核对自 misago/misagodocker/settings.py 与 docker-compose.yaml):

层一:compose 宿主插值变量(docker compose up 时在宿主 shell 插值,不走 env_file,用于数据库连接参数):

变量默认值(compose 内定义)作用
MISAGO_POSTGRES_DBmisagodb数据库名(注入 postgres 与 misago/celery 的 POSTGRES_DB)
MISAGO_POSTGRES_USERmisagodb数据库用户(注入 POSTGRES_USER)
MISAGO_POSTGRES_PASSWORDmisagodbpassword数据库口令(注入 POSTGRES_PASSWORD)
MISAGO_POSTGRES_HOSTpostgres-15数据库主机(注入 misago/celery 的 POSTGRES_HOST)

⚠️ 坑(实测核对 .run 脚本):容器内辅助脚本 ./.run 的 wait_for_db/psql/backup 用 psql -d $POSTGRES_USER 连库——库名必须等于用户名,即 MISAGO_POSTGRES_DB 与 MISAGO_POSTGRES_USER 必须设同值,否则备份/psql/初始化全部连不上。默认值 misagodb/misagodb 恰好满足。

层二:config/misago.env(env_file,misago 与 celery-worker 共用):

变量必填默认(settings.py)作用
MISAGO_SECRET_KEY是无(None)Django SECRET_KEY,会话/CSRF 签名
MISAGO_DEBUG是无(strtobool 直接解析)调试模式 no/yes
MISAGO_ADDRESS建议—站点地址,供 appctl 向导族使用(Django settings 不读)
MISAGO_LANGUAGE_CODE否en-us界面语言
MISAGO_TIME_ZONE否UTC时区
MISAGO_SEARCH_CONFIG否simplePostgreSQL 全文检索配置
MISAGO_INDEX否threads首页形态:threads=帖子列表 / categories=版块索引
MISAGO_EMAIL_PROVIDER否其它值→console邮件通道:smtp/gmail/mailjet/sendinblue/console
MISAGO_EMAIL_HOST 等 6 键smtp 时必填—MISAGO_EMAIL_USE_SSL/USE_TLS/HOST/PORT/USER/PASSWORD
MISAGO_DEFAULT_FROM_EMAIL建议空串发件人
MISAGO_DAILY_BACKUP否—向导记录项(yes/no),备份定时由 appctl set_crontab 落地

层三:settings.py/镜像读取的其他变量(compose environment 或 Dockerfile ENV 注入,一般无需改):

变量默认值作用
POSTGRES_DB/USER/PASSWORD/HOST由层一插值注入settings.py DATABASES 直读(PORT 固定 5432)
VIRTUAL_HOST—→ ALLOWED_HOSTS(逗号分隔 strtolist);同时是 nginx-proxy 生成 server_name/upstream 的依据
CACHE_REDIS_URLredis://redis-6/1Django RedisCache(含会话)
CELERY_BROKER_URLredis://redis-6/0Celery 队列
CELERY_WORKER_MAX_TASKS_PER_CHILD10worker 每 10 任务重启防内存膨胀
MISAGO_PLUGINS/misago/plugins(Dockerfile ENV)插件发现目录
SENTRY_DSN未设=禁用Sentry 错误上报
SSL_POLICYMozilla-Modern(compose 注入 nginx-proxy)代理 TLS 策略
VIRTUAL_PROTOuwsgi(compose 注入 misago)告知 nginx-proxy 用 uwsgi_pass 而非 http
ENABLE_IPV6truenginx-proxy/postgres 开 IPv6 监听

七、配置参数说明

Misago 的配置是四层模型(逐层语义、默认值与生效机制的详解专篇见《Misago 0.39.6 配置参数详解》,此处只给部署视角速览):

层载体修改方式生效条件
环境变量层config/misago.env + compose environment编辑文件 / `./appctl hostnameemail
settings.py 层misago/misagodocker/settings.py(484 行,env→Django 映射)一般不动—
override 层misago/misagodocker/settings_override.py(默认不存在,需创建)新建文件写入 Django 变量需 ./appctl rebuild(文件烘焙进镜像)
动态设置层管理后台 /admincp/(存 misago_conf 表)浏览器操作即时生效,免重启

部署完成后的配置自检(实测回显):

./appctl manage.py diffsettings | grep -E '^ALLOWED_HOSTS|^MISAGO_THREADS_ON_INDEX'
ALLOWED_HOSTS = ['192.168.1.172']
MISAGO_THREADS_ON_INDEX = False  ###

MISAGO_THREADS_ON_INDEX = False 即 MISAGO_INDEX=categories 的映射结果(False=版块索引首页),行尾 ### 是 diffsettings 对 Misago 自定义项(非 Django 标准 settings)的标记;diffsettings 默认只列出与 Django 全局默认不同的项与自定义项。

八、配置文件挂载

部署包内需要认识的四个配置挂载点(compose volumes 实测核对):

  1. ./config/misago.env:env_file 机制同时注入 misago 与 celery-worker 两个服务——这是 VIRTUAL_HOST 污染 upstream 坑的根源(FAQ 11.3),单服务专属变量务必放 override 的 environment: 而非此文件;
  2. misago/misagodocker/settings_override.py 与 urls_override.py:不在挂载列表里——它们随 Dockerfile 的 COPY . /misago 烘焙进镜像(官方 README 指明与 settings.py 同目录),宿主编辑后必须 ./appctl rebuild 才生效;
  3. ./config/vhost.d:挂载进 nginx-proxy /etc/nginx/vhost.d,按域名放 nginx 片段(如 192.168.1.172.location)做代理级定制,docker-gen reload 时自动 include;
  4. ./misago/theme(ro):主题覆盖点,放自定义模板/静态文件;只读挂载进应用与 celery 两容器。

九、等价 docker run

官方编排是六服务 compose 栈;对应用服务(misago)可给出等价 docker run 形态(网络、卷、env_file 逐项对应)。语法实测验证(用 python --version 替代启动命令做一次性运行,不产生常驻容器):

docker run --rm \
  --network misago_docker_misago \
  --env-file config/misago.env \
  -e POSTGRES_HOST=postgres-15 -e POSTGRES_DB=misagodb \
  -e POSTGRES_USER=misagodb -e POSTGRES_PASSWORD=misagodbpassword \
  -e SSL_POLICY=Mozilla-Modern -e VIRTUAL_PROTO=uwsgi -e VIRTUAL_HOST=192.168.1.172 \
  -v $(pwd)/misago/media:/misago/media:z \
  -v $(pwd)/misago/static:/misago/static:z \
  -v $(pwd)/misago/avatargallery:/misago/avatargallery:ro \
  -v $(pwd)/misago/theme:/misago/theme:ro \
  -v $(pwd)/backups:/misago/backups:Z \
  -v $(pwd)/logs:/misago/logs:z \
  misago_docker-misago:latest python --version

实测回显:

Python 3.12.16

把命令换成 uwsgi --ini uwsgi.ini(镜像 CMD 默认值)即常驻应用;celery-worker 等价形态为同镜像 + 命令 celery -A misagodocker worker --loglevel=info。postgres/redis 即标准官方镜像单容器运行。代理层注意:nginx-proxy 依赖挂载 /var/run/docker.sock 事件驱动生成 upstream 配置,纯 docker run 形态下它同样能工作(按容器 VIRTUAL_HOST 环境变量识别),但失去了 depends_on/网络别名的编排保障;若完全不用 nginx-proxy,需自备 Nginx 并手工写 uwsgi_pass misago:3031 + include uwsgi_params 的反代片段(对应实测生成配置见 FAQ 11.5 的 upstream/server 块)。生产环境建议保持官方 compose 编排。

十、常用运维命令速查

部署包根目录的 ./appctl 是运维主入口(全部子命令与逐条实测详解见《Misago 0.39.6 常用 CLI 命令与工具详解》):

./appctl start / stop / restart     # 起停全部容器
./appctl stats                      # 容器资源一览(流式 docker stats,Ctrl+C 退出)
./appctl backup                     # 数据库+媒体打包备份
./appctl flushredis                 # 清 Redis 缓存(会登出全部用户,交互确认)
./appctl manage.py <命令>           # 透传 Django 管理命令
./appctl bash                       # 进入应用容器 shell
./appctl psql                       # 连接数据库 psql

关键命令实测回显示例:

echo "SELECT version();" | ./appctl psql
PostgreSQL 15.19 (Debian 15.19-1.pgdg13+2) on x86_64-pc-linux-gnu, compiled by gcc (Debian 14.2.0-19) 14.2.0, 64-bit
(1 row)
./appctl backup
Initializing backup manual-20261102152126
Preparing database...
Preparing media files...
Archiving...
Cleaning up...
New backup: manual-20261102152126.tar.gz
echo n | ./appctl flushredis
  - Remove all cached information
  - Close all user sessions (log all users out)

Cache flush canceled.

十一、常见问题(排障实录)

11.1 宿主 80/443 被占用,override 改端口后仍冲突

现象:override 写了 ports: ["192.168.1.172:8128:80"],docker compose config 仍显示 80/443 发布,启动报端口冲突。 定位:compose 对 ports 列表的合并语义是追加而非替换,基础编排的 80:80、443:443 依然生效。 解决:override 里用 ports: !override 标签整段替换(4.3 文件第一处适配)。 验证:docker compose config | grep -A2 ports 只剩 8128 行;ss -ltn | grep 8128 见 192.168.1.172:8128 监听。

11.2 不启用 letsencrypt 后 nginx-lets-encrypt 服务仍被拉起

现象:只想 HTTP 部署,但 docker compose up -d 仍启动证书签发容器并因无域名循环报错。 定位:基础编排 misago 服务 depends_on 列表含 nginx-lets-encrypt;且 depends_on 短列表被 compose 归一化为 map 合并,override 无法删列表项。 解决:双管齐下(4.3 文件)——给 nginx-lets-encrypt 加 profiles: [letsencrypt] 移出默认启动集;misago 的 depends_on 改长格式 nginx-lets-encrypt: {required: false}(Compose v2.20+/本实测 v5.6.1 支持)。 验证:docker compose config --services 回显 5 服务(无 nginx-lets-encrypt),见 4.3 实测输出。

11.3 celery-worker 混入 nginx upstream,error.log 刷 connect() failed

现象:站点能访问,但代理 error.log 大量 connect() failed (111: Connection refused) while connecting to upstream,upstream 里出现第二个 server(celery 容器 IP:3031)。 定位:nginx-proxy 的 docker-gen 按 VIRTUAL_HOST 环境变量分组生成 upstream;celery-worker 与 misago 共用 env_file,VIRTUAL_HOST 写在 misago.env 里导致 celery 也被注册——而 celery 进程根本不监听 3031。GET 幂等请求因 nginx 重试+临时禁用(max_fails=1/10s)仍全 200,但非幂等请求(发帖/登录 POST)存在 502 风险。 解决:见 11.5 最终修法。

11.4 createsuperuser --noinput 静默不建用户

现象:docker compose run --rm misago python manage.py createsuperuser --noinput --username admin --email admin@example.com 退出码 0,但用户不存在。 定位:Misago 自带(users 应用覆盖的)createsuperuser 支持原生 --password 参数且不读 Django 惯例的 DJANGO_SUPERUSER_PASSWORD;--noinput 下拿不到密码即静默跳过。 解决:显式传 --password(4.5 命令),回显 Superuser #1 has been created successfully. 才算建成。

11.5 修复 VIRTUAL_HOST 污染:空串赋值导致 nginx 配置语法崩溃

现象:试图用 override 给 celery-worker 设 VIRTUAL_HOST=(空串)来"摘除"它,nginx-proxy reload 失败:nginx: [emerg] invalid number of arguments in "upstream" directive,此时线上仅靠内存里的旧配置在跑,任何 reload 都会炸。 定位:docker-gen 对空 VIRTUAL_HOST 的容器生成了匿名 upstream {} 与 server_name ; 残缺配置。 解决(最终版):把 VIRTUAL_HOST 从 config/misago.env 移除,只在 override 的 misago 服务 environment: 注入(celery 无该变量则 docker-gen 直接忽略,而不是生成空块)。 验证(实测回显):

docker compose exec nginx-proxy grep -A4 'upstream 192.168.1.172' /etc/nginx/conf.d/default.conf
upstream 192.168.1.172 {
				## Can be connected with "misago_docker_misago" network
			# misago_docker-misago-1
			server 10.89.56.5:3031;
}

upstream 只剩 misago 一个 server;代理配置语法校验通过:

docker compose exec nginx-proxy nginx -t

实测回显:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

50 连发全 200(4.6)。

11.6 docker compose run 时宿主临时变量不透传

现象:VAR=x docker compose run --rm misago env | grep VAR 无任何输出——容器内读不到宿主临时变量 VAR。 定位:docker compose run 只注入 compose 文件声明过的变量(environment/env_file),宿主未声明变量不会透传——与 docker run -e 习惯不同。 解决:在 compose/override 的 environment: 声明该变量(可写 ${VAR} 引用宿主值),或 docker compose run -e VAR=x。

十二、参考链接

Misago 0.39.6 Docker Compose 部署指南 - Quzuo