Misago 0.39.6 Docker Compose 部署指南
用官方 misago_docker 部署包以 Docker Compose 从零构建上线 Misago 0.39.6 五服务栈:非交互初始化、环境变量表、数据持久化、等价 docker run,完整沉淀端口占用、证书隔离与 celery 混入 upstream 排障实录。
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):
| 服务 | 内存占用 | 说明 |
|---|---|---|
| misago | 139.4 MiB | uWSGI 主应用(4 worker) |
| celery-worker | 355.3 MiB | Celery worker(与主应用同镜像) |
| nginx-proxy | 42.1 MiB | 反向代理 |
| postgres-15 | 21.4 MiB | 空库 + 少量测试数据 |
| redis-6 | 2.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) | latest | 2.13GB(内容 551MB) | uWSGI 主应用 |
misago_docker-celery-worker | 本地构建(同一 Dockerfile) | latest | 同上(层共享) | Celery worker |
misago_docker-nginx-proxy | 本地构建(nginx-proxy/ 目录) | latest | 271MB(内容 74.6MB) | 反向代理(docker-gen 动态配置) |
postgres:15 | Docker Hub 官方 | 15.19 | — | 主存储 + 全文检索 |
redis:6 | Docker Hub 官方 | 6.x | — | 缓存/会话 + 队列 |
jrcs/letsencrypt-nginx-proxy-companion:2.2 | Docker Hub | 2.2 | — | 自动签发 TLS(本实测未启用) |
版本锁定机制:应用版本由部署包仓库的 misago/requirements.in 钉住(当前 misago==0.39.6),没有可选的镜像 tag——升级 = 更新部署包(./appctl upgrade 走 git pull + rebuild),而非改 tag。
💡 技术拓展:论坛类软件的容器交付物形态主要有三类,对比——
形态 代表 特点 取舍 官方预构建镜像 + 版本 tag Mastodon、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,无需任何额外配置。
三、前置条件
-
Docker 与 Compose 插件:宿主机安装 Docker 24+ 与
docker composev2+ 插件。验证:docker compose version实测回显:
Docker Compose version v5.6.1 -
端口规划:基础编排默认发布
80:80、443:443。本实测宿主 80/443 已被既有服务占用,改走192.168.1.172:8128IP 绑定发布。确认目标端口空闲:ss -ltn | grep ':8128'实测回显(规划时无输出 = 端口空闲;后续被本栈占用后回显监听行):
LISTEN 0 4096 192.168.1.172:8128 0.0.0.0:* -
网段规划:编排使用自定义网络,多栈共存建议显式指定子网避免冲突。查看已占用网段:
docker network ls && docker network inspect <已有栈网络> -f '{{range .IPAM.Config}}{{.Subnet}}{{end}}'本文实测选用空闲网段
10.89.56.0/24(见 4.3 override)。 -
资源:五服务常驻约 561MiB(第一章实测表)+ 构建期峰值,建议 ≥2GB 内存、预留 8GB 磁盘(构建镜像约 2.4GB + 数据目录)。
-
域名与邮件规划:生产站点需要域名(
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:基础编排里 misagodepends_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 volume | misago-postgres-15 → /var/lib/postgresql/data | 随数据增长 | 帖子/用户/动态设置全在此 |
| Redis 数据 | named volume | misago-redis-6 → /data | 2.9MiB | 缓存/会话/队列,可丢(丢=全员登出) |
| TLS 证书 | named volume | nginx-certs、nginx-html、lets-encrypt-acme | 空(未启用证书) | 启用 letsencrypt 后落这里 |
| 用户上传媒体 | bind | ./misago/media → /misago/media | 2.7M | 头像、附件 |
| 静态资产 | bind | ./misago/static → /misago/static | 37M | collectstatic 产物 |
| 头像库 | bind 只读 | ./misago/avatargallery → /misago/avatargallery:ro | 2.3M | loadavatargallery 产物 |
| 主题覆盖 | bind 只读 | ./misago/theme → /misago/theme:ro | 20K | 自定义模板/静态覆盖点 |
| 备份归档 | bind | ./backups → /misago/backups | 2.2M/份 | appctl backup 产物 |
| 应用日志 | bind | ./logs → /misago/logs(nginx 日志在 ./logs/nginx) | 216K | misago.log/celery.log/uwsgi.log,周轮转,60 天清理 |
| nginx 站点片段 | bind | ./config/vhost.d → /etc/nginx/vhost.d | 12K | 按域名注入代理片段 |
备份归档结构实测(./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_DB | misagodb | 数据库名(注入 postgres 与 misago/celery 的 POSTGRES_DB) |
MISAGO_POSTGRES_USER | misagodb | 数据库用户(注入 POSTGRES_USER) |
MISAGO_POSTGRES_PASSWORD | misagodbpassword | 数据库口令(注入 POSTGRES_PASSWORD) |
MISAGO_POSTGRES_HOST | postgres-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 | 否 | simple | PostgreSQL 全文检索配置 |
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_URL | redis://redis-6/1 | Django RedisCache(含会话) |
CELERY_BROKER_URL | redis://redis-6/0 | Celery 队列 |
CELERY_WORKER_MAX_TASKS_PER_CHILD | 10 | worker 每 10 任务重启防内存膨胀 |
MISAGO_PLUGINS | /misago/plugins(Dockerfile ENV) | 插件发现目录 |
SENTRY_DSN | 未设=禁用 | Sentry 错误上报 |
SSL_POLICY | Mozilla-Modern(compose 注入 nginx-proxy) | 代理 TLS 策略 |
VIRTUAL_PROTO | uwsgi(compose 注入 misago) | 告知 nginx-proxy 用 uwsgi_pass 而非 http |
ENABLE_IPV6 | true | nginx-proxy/postgres 开 IPv6 监听 |
七、配置参数说明
Misago 的配置是四层模型(逐层语义、默认值与生效机制的详解专篇见《Misago 0.39.6 配置参数详解》,此处只给部署视角速览):
| 层 | 载体 | 修改方式 | 生效条件 |
|---|---|---|---|
| 环境变量层 | config/misago.env + compose environment | 编辑文件 / `./appctl hostname | |
| 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 实测核对):
./config/misago.env:env_file 机制同时注入 misago 与 celery-worker 两个服务——这是 VIRTUAL_HOST 污染 upstream 坑的根源(FAQ 11.3),单服务专属变量务必放 override 的environment:而非此文件;misago/misagodocker/settings_override.py与urls_override.py:不在挂载列表里——它们随Dockerfile的COPY . /misago烘焙进镜像(官方 README 指明与 settings.py 同目录),宿主编辑后必须./appctl rebuild才生效;./config/vhost.d:挂载进 nginx-proxy/etc/nginx/vhost.d,按域名放 nginx 片段(如192.168.1.172.location)做代理级定制,docker-gen reload 时自动 include;./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 官网:https://misago-project.org/
- 官方部署包仓库(本实测 HEAD 275343f):https://github.com/rafalp/misago_docker
- 官方部署包 README(setup 向导/备份/主题覆盖说明):https://github.com/rafalp/misago_docker#readme
- Misago 官方文档:https://misago.gitbook.io/docs/setup
- Misago GitHub 仓库:https://github.com/rafalp/Misago
- 官方支持论坛(Docker 版块):https://misago-project.org/c/docker/27/
- nginx-proxy(jwilder):https://github.com/nginx-proxy/nginx-proxy
- 站内配套阅读:《Misago 0.39.6 介绍与选型指南》、《Misago 0.39.6 配置参数详解》、《Misago 0.39.6 常用 CLI 命令与工具详解》