Mathesar 0.12.0 Docker Compose 部署指南

官方 Compose 三服务(应用/内置 PostgreSQL/Caddy)从零部署 Mathesar 0.12.0 全流程:启动与就绪验证实测回显、内置库与外部 PostgreSQL 16 双形态接入、bind mount 持久化与 down/up 销毁性验证、环境变量表、等价 docker run 与运维 FAQ。

MathesarMathesar2026/10/30

Mathesar 0.12.0 Docker Compose 部署指南

目标:用官方 Docker Compose 从零把 Mathesar 0.12.0 跑起来并完成首次安装,覆盖「内置数据库」与「连接外部已有 PostgreSQL」两种形态、数据持久化验证与常用运维。全部步骤与回显均在 Ubuntu 22.04 宿主上实测(Mathesar 0.12.0 + PostgreSQL 17.6 内置库 + PostgreSQL 16.15 外部库)。

一、环境信息

  • 操作系统:Ubuntu 22.04(x86_64,Linux 5.15)
  • Docker:24.x / Compose v2(docker compose 子命令可用)
  • Mathesar:0.12.0(mathesar/mathesar:0.12.0,约 2.24 GB)
  • 反向代理:mathesar/mathesar-caddy:latest(约 1.65 GB,随官方 compose 一起提供)
  • 内置数据库:pgautoupgrade/pgautoupgrade:17-bookworm(约 1.13 GB,提供 PostgreSQL 17.6)
  • 外部数据库(形态 B 实测用):postgres:16-alpine(PostgreSQL 16.15)
  • 网络规划:Compose 默认网络 mathesar-0120-stack-net;Web 入口宿主端口 8128(宿主 80 已被占用,故改映射);外部 PG 映射宿主端口 8129
  • 部署目录:/opt/mathesar/(本文以该路径书写,实测部署即采用该目录布局)

⚠️ 说明:官方 docker-compose.yml 原样使用 80/443 端口与 latest 应用 tag。本文为在本机完成实测做了三处本地适配并逐处标注:1) Caddy 宿主端口 80→8128(443 映射移除,因为 DOMAIN_NAME 使用 http);2) 显式 name: mathesar-0120-stack 项目名与固定网段;3) 应用镜像 tag 由 latest 锁定为 0.12.0(版本可复现)。读者可按需保留官方原值。

二、镜像选型说明

官方 compose 一共用到三个镜像,均有明确分工:

镜像角色说明
mathesar/mathesar:0.12.0应用服务Django + Gunicorn(监听 8000,仅内网 expose,不直接对外),含完整 Web UI 与 JSON-RPC API
pgautoupgrade/pgautoupgrade:17-bookworm内置 PostgreSQLMathesar 官方选定的基础库镜像;特色是启动时自动执行大版本升级(17-bookworm 表示 PG 17),承载元数据库 mathesar_django 与(可选的)业务库
mathesar/mathesar-caddy:latest反向代理内置 Mathesar 专用 Caddyfile,负责 /static/*、/media/* 文件直出与其余流量反代到 mathesar_service:8000,对外暴露 80/443

选型要点:应用与 Caddy 镜像均为 Mathesar 官方构建发布;若追求版本锁定,把 mathesar/mathesar-caddy:latest 也固定到与官方 release 对应的 tag(本实测环境沿用 latest,启动正常);pgautoupgrade 镜像的「自动大版本升级」特性适合长期运行的内置库形态。

三、前置条件

  1. 宿主已安装 Docker 与 Compose v2:docker compose version 能正常输出版本。
  2. 宿主 80(或你自定义的映射端口,如 8128)未被占用:ss -ltnp | grep -E ':80 |:8128 ' 应无输出或非目标进程。
  3. 磁盘余量 ≥ 6 GB(三个镜像合计约 5 GB,加上数据目录)。
  4. 可访问 Docker Hub(或已配置镜像加速/代理)。

验证宿主就绪的实测回显:

$ docker compose version
Docker Compose version v2.x
$ ss -ltn | grep 8128
(无输出,端口可用)

四、部署步骤

4.1 建目录并写入 compose 文件

mkdir -p /opt/mathesar && cd /opt/mathesar
mkdir -p msar/static msar/media msar/secrets msar/caddy msar/pgdata
vi docker-compose.yml

docker-compose.yml 全文(官方 0.12.0 版 compose + 本文三处适配,适配处均有注释):

name: mathesar-0120-stack

x-config: &config
  DOMAIN_NAME: ${DOMAIN_NAME:-http://localhost}
  POSTGRES_DB: ${POSTGRES_DB:-mathesar_django}
  POSTGRES_USER: ${POSTGRES_USER:-mathesar}
  POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-mathesar}
  POSTGRES_HOST: ${POSTGRES_HOST:-mathesar_db}
  POSTGRES_PORT: ${POSTGRES_PORT:-5432}
  FILE_STORAGE_DICT: ${FILE_STORAGE_DICT:-{}}
  SSO_CONFIG_DICT: ${SSO_CONFIG_DICT:-{}}
  OIDC_CONFIG_DICT: ${OIDC_CONFIG_DICT:-{}} # deprecated, use SSO_CONFIG_DICT
  REQUIRE_SSO_LOGIN: ${REQUIRE_SSO_LOGIN:-false}
  MATHESAR_DJANGO_ADMIN_ENABLED: ${MATHESAR_DJANGO_ADMIN_ENABLED:-false}
  MATHESAR_LANDING_PAGE_URL: ${MATHESAR_LANDING_PAGE_URL:-}
  MATHESAR_INSTANCE_NAME: ${MATHESAR_INSTANCE_NAME:-Mathesar}
  MATHESAR_AUTH_LOGO_URL: ${MATHESAR_AUTH_LOGO_URL:-}
  MATHESAR_LOGIN_PAGE_TEXT_DICT: ${MATHESAR_LOGIN_PAGE_TEXT_DICT:-{}}
  MATHESAR_LOGIN_PAGE_BACKGROUND: ${MATHESAR_LOGIN_PAGE_BACKGROUND:-}
  MATHESAR_TERMS_OF_SERVICE_URL: ${MATHESAR_TERMS_OF_SERVICE_URL:-}
  MATHESAR_PRIVACY_POLICY_URL: ${MATHESAR_PRIVACY_POLICY_URL:-}

services:
  service:
    container_name: mathesar_service
    image: mathesar/mathesar:0.12.0        # 官方为 mathesar/mathesar:latest,本文锁定 0.12.0
    environment:
      <<: *config
      DJANGO_SETTINGS_MODULE: config.settings.production
      ALLOWED_HOSTS: ${ALLOWED_HOSTS:-*}
      DEBUG: ${DEBUG:-false}
      SECRET_KEY: ${SECRET_KEY-}
      WEB_CONCURRENCY: ${WEB_CONCURRENCY-3}
      PER_USER_DATABASES_ENABLED: ${PER_USER_DATABASES_ENABLED-false}
    volumes:
      - ./msar/static:/code/static
      - ./msar/media:/code/.media
      - ./msar/secrets:/code/.secrets
    depends_on:
      db:
        condition: service_healthy
    healthcheck:
      test: curl -f http://localhost:8000/healthz/ready/
      interval: 10s
      timeout: 5s
      retries: 30
      start_period: 5s
    expose:
      - "8000"

  db:
    image: pgautoupgrade/pgautoupgrade:17-bookworm
    container_name: mathesar_db
    environment: *config
    expose:
      - "5432"
    volumes:
      - ./msar/pgdata:/var/lib/postgresql/data

  caddy-reverse-proxy:
    image: mathesar/mathesar-caddy:latest
    environment: *config
    ports:
      - "8128:80"                           # 官方为 "80:80"(及 "443:443"),本机 80 被占用改为 8128
    volumes:
      - ./msar/media:/code/.media
      - ./msar/static:/code/static
      - ./msar/caddy:/data

networks:
  default:
    name: mathesar-0120-stack-net
    driver: bridge
    ipam:
      config:
        - subnet: 10.89.56.0/24

配置解读:

  • x-config 锚点把三个服务共用的环境变量收拢到一处,service 与 db 都通过 *config 继承,改一处全局生效。
  • service.depends_on.db.condition: service_healthy 保证数据库完全就绪后应用才启动——这是首次启动时 mathesar_service 会等待较长时间的原因。
  • service 只 expose 8000 不映射宿主端口,外部访问一律经 Caddy;db 同理只在内网 expose 5432。
  • 三个 bind mount 目录都落在部署目录下的 msar/ 内,备份/迁移只需带走整个 /opt/mathesar/。

4.2 启动

cd /opt/mathesar && docker compose up -d

实测回显(首次创建):

 Container mathesar-0120-stack-caddy-reverse-proxy-1 Creating
 Container mathesar_db Creating
 Container mathesar-0120-stack-caddy-reverse-proxy-1 Created
 Container mathesar_db Created
 Container mathesar_service Creating
 Container mathesar_service Created
 Container mathesar-0120-stack-caddy-reverse-proxy-1 Starting
 Container mathesar_db Starting
 Container mathesar-0120-stack-caddy-reverse-proxy-1 Started
 Container mathesar_db Started
 Container mathesar_db Waiting
 Container mathesar_db Healthy
 Container mathesar_service Starting
 Container mathesar_service Started

观察点:mathesar_db Waiting → Healthy 即 depends_on 条件在生效;应用容器要等数据库健康检查通过才 Starting。首次拉取镜像耗时取决于网络,三个镜像约 5 GB。

4.3 验证就绪

# 1) 三个服务全部 Up,service/db 显示 (healthy)
docker compose ps
# 2) 应用健康检查端点
curl -s http://localhost:8128/healthz/ready/
# 3) 未登录访问根路径应 302 到登录页
curl -s -o /dev/null -w '%{http_code} -> %{redirect_url}\n' http://localhost:8128/

实测回显:

$ docker compose ps
NAME                                        IMAGE                                     SERVICE               STATUS                 PORTS
mathesar-0120-stack-caddy-reverse-proxy-1   mathesar/mathesar-caddy:latest            caddy-reverse-proxy   Up 2 hours             443/tcp, 2019/tcp, 443/udp, 0.0.0.0:8128->80/tcp
mathesar_db                                 pgautoupgrade/pgautoupgrade:17-bookworm   db                    Up 2 hours (healthy)   5432/tcp
mathesar_service                            mathesar/mathesar:0.12.0                  service               Up 2 hours (healthy)   5432/tcp, 8000/tcp

$ curl -s http://localhost:8128/healthz/ready/
{"status": "ok"}

$ curl -s -o /dev/null -w '%{http_code} -> %{redirect_url}\n' http://localhost:8128/
302 -> http://localhost:8128/auth/login/?next=/

服务启动日志(docker compose logs service --tail 20 节选,实测):

==> Starting Mathesar...
==> Running Django setup...
    Operations to perform:
      Apply all migrations: account, auth, contenttypes, mathesar, sessions, socialaccount
    Running migrations:
      No migrations to apply.

No migrations to apply 表示元数据库结构已是最新(首次全新部署这里会执行一批 CREATE TABLE,属正常差异)。

4.4 首次安装向导与登录

浏览器打开 http://<宿主IP>:8128/,全新实例会进入安装向导(对应应用内 /complete_installation/ 路由),按页面提示创建管理员账号后即完成安装。本文演示实例创建的管理员为:

  • 用户名:admin
  • 密码:q1w2e3r4

登录后进入库/表导航界面;http://localhost:8128/auth/login/ 是登录页固定地址(根路径未登录会被 302 到这里,实测见 4.3)。

4.5 形态 B:连接外部已有 PostgreSQL

Mathesar 的数据面不依赖内置库——它可以同时管理多个 PostgreSQL 服务器。实测在保留内置库的前提下,把一台外部 PostgreSQL 16.15 挂进同一网络并接入 Mathesar:

第一步,准备外部实例(已有多台 PG 的读者可跳过这一步,只需保证 Mathesar 能连通其 host:port):

# 外部 PostgreSQL 16 实例,数据目录同样落在部署目录下
docker run -d --name mathesar-0.12.0-extpg \
  --network mathesar-0120-stack-net \
  -p 8129:5432 \
  -e POSTGRES_USER=pgadmin \
  -e POSTGRES_PASSWORD=q1w2e3r4 \
  -e POSTGRES_DB=business \
  -v /opt/mathesar/extpg-data:/var/lib/postgresql/data \
  postgres:16-alpine

实测版本确认(外部库内执行 SELECT version() 的回显):

PostgreSQL 16.15 on x86_64-pc-linux-musl, compiled by gcc (Alpine 15.2.0) 15.2.0, 64-bit

第二步,接入 Mathesar——两种等价入口任选:

  • Web UI:登录后进入「数据库」管理入口,选择连接已有数据库,填 Host mathesar-0.12.0-extpg(同网络实例名/主机名)、端口 5432、库名 business、角色 pgadmin、密码 q1w2e3r4;
  • RPC 接口:用管理员会话调用 databases.setup.connect_existing(JSON-RPC,认证与调用方式见《Mathesar 0.12.0 API 使用详解》)。

接入成功的实测回显(databases.configured.list 返回两库,外部库 server_id=2):

[{"id": 1, "name": "warehouse", "server_id": 1, "last_confirmed_sql_version": "0.12.0", "needs_upgrade_attention": false, "nickname": "仓储示例库"},
 {"id": 2, "name": "business", "server_id": 2, "last_confirmed_sql_version": "0.12.0", "needs_upgrade_attention": false, "nickname": "外部业务库"}]

servers.configured.list 同时返回两个 server(实测):

[{"id": 1, "host": "mathesar_db", "port": 5432, "sslmode": "prefer"},
 {"id": 2, "host": "mathesar-0.12.0-extpg", "port": 5432, "sslmode": "prefer"}]

⚠️ 注意:Mathesar 连接外部库时会在目标库内安装 msar 函数 schema(实测外部库接入后同样出现 msar/__msar/mathesar_types),这是它的数据操作层,属预期行为;角色需具备建 schema 权限(本文用 pgadmin 超级角色无障碍)。

五、数据持久化说明

所有持久化数据都通过 bind mount 落在部署目录 /opt/mathesar/ 内:

宿主路径挂载点内容
./msar/pgdata/var/lib/postgresql/data(db 服务)PostgreSQL 数据目录:元数据库 mathesar_django + 内置形态的业务库
./msar/secrets/code/.secrets(service 服务)自动生成的 SECRET_KEY 文件等
./msar/static/code/static(service 与 caddy 共享)Web UI 静态资源(启动时由应用落盘,Caddy 直出)
./msar/media/code/.media(service 与 caddy 共享)用户上传/导入的数据文件
./msar/caddy/data(caddy 服务)Caddy 数据(证书等)
./extpg-data/var/lib/postgresql/data(外部 PG)形态 B 的外部库数据

销毁性实测验证:把整套服务 docker compose down 后重新 up -d,数据完好——records.list 仍返回原有行(关羽/张飞等),databases.configured.list 中外部库配置仍在,健康检查恢复 200。也就是说 down 不触碰 bind mount 数据;只有删除宿主 msar/ 目录本身才会真正丢数据。

六、环境变量表

以下变量实测自 0.12.0 官方 compose 的 x-config 与 service 环境(docker compose exec service printenv 全量核对):

变量默认值(compose)说明
DOMAIN_NAMEhttp://localhost站点对外地址;Caddy 以它作为站点名(含协议),反代与静态路径都挂在其下
POSTGRES_DB / POSTGRES_USER / POSTGRES_PASSWORDmathesar_django / mathesar / mathesar元数据库连接三元组,db 与 service 共用
POSTGRES_HOST / POSTGRES_PORTmathesar_db / 5432元数据库地址
DJANGO_SETTINGS_MODULEconfig.settings.production应用固定使用生产 settings(compose 内写死)
ALLOWED_HOSTS*Django 允许的 Host 头;生产建议收敛为具体域名
DEBUGfalseDjango 调试开关,生产保持 false
SECRET_KEY空会话签名密钥;留空时应用自动生成并写入 /code/.secrets/secret_key.txt(见 4.7 常见问题)
WEB_CONCURRENCY3Gunicorn worker 数(实测进程树:1 主 + 3 worker)
PER_USER_DATABASES_ENABLEDfalse是否启用「按用户隔离数据库」模式
FILE_STORAGE_DICT{}下载链接文件存储后端配置(JSON;也支持 /code/file_storage.yml)
SSO_CONFIG_DICT{}SSO 配置(JSON),0.12.0 起的规范入口
OIDC_CONFIG_DICT{}旧版 OIDC 配置入口,保留兼容,官方标注 deprecated
REQUIRE_SSO_LOGINfalse为 true 时强制 SSO 登录(本地口令登录被关闭)
MATHESAR_DJANGO_ADMIN_ENABLEDfalse是否开启 Django 原生 /admin/ 后台
MATHESAR_LANDING_PAGE_URL空未登录时根路径重定向到该地址(留空走默认登录页)
MATHESAR_INSTANCE_NAMEMathesar站点显示名
MATHESAR_AUTH_LOGO_URL空登录页 Logo
MATHESAR_LOGIN_PAGE_TEXT_DICT{}登录页文案配置(JSON;也支持 /code/login_page.yml)
MATHESAR_LOGIN_PAGE_BACKGROUND空登录页背景
MATHESAR_TERMS_OF_SERVICE_URL / MATHESAR_PRIVACY_POLICY_URL空服务条款/隐私政策链接

各变量与 Django settings 的映射细节、取值格式,见《Mathesar 0.12.0 配置参数详解》。

七、配置文件挂载

本部署形态下需要手工维护的配置文件为零——所有配置走环境变量。三个「可选配置文件」通过 YAML 提供更复杂的结构(挂到 /code/ 下即生效,优先级低于同名环境变量,实测自 settings 源码):

  • /code/sso.yml:SSO/OIDC 与 GitHub App 配置(当 SSO_CONFIG_DICT 的 JSON 过长不便维护时使用);
  • /code/login_page.yml:登录页文案;
  • /code/file_storage.yml:下载链接的文件存储后端(fsspec URI)。

如需使用,在 service 服务的 volumes 里追加一行挂载即可,例如:

    volumes:
      - ./msar/static:/code/static
      - ./msar/media:/code/.media
      - ./msar/secrets:/code/.secrets
      - ./sso.yml:/code/sso.yml:ro

八、等价 docker run

不用 Compose 时,以下三条命令等价复现官方三服务拓扑(同一自定义网络内,注意启动顺序:先 db,再 service,最后 caddy):

# 1) 网络
docker network create mathesar-net

# 2) 内置 PostgreSQL(先启动,等它健康后再起应用)
docker run -d --name mathesar_db --network mathesar-net \
  -e POSTGRES_DB=mathesar_django -e POSTGRES_USER=mathesar -e POSTGRES_PASSWORD=mathesar \
  -e DOMAIN_NAME=http://localhost \
  -v /opt/mathesar/msar/pgdata:/var/lib/postgresql/data \
  pgautoupgrade/pgautoupgrade:17-bookworm

# 3) Mathesar 应用(SECRET_KEY 留空则自动生成到挂载的 secrets 目录)
docker run -d --name mathesar_service --network mathesar-net \
  -e DOMAIN_NAME=http://localhost \
  -e POSTGRES_DB=mathesar_django -e POSTGRES_USER=mathesar -e POSTGRES_PASSWORD=mathesar \
  -e POSTGRES_HOST=mathesar_db -e POSTGRES_PORT=5432 \
  -e DJANGO_SETTINGS_MODULE=config.settings.production \
  -e ALLOWED_HOSTS='*' -e DEBUG=false -e WEB_CONCURRENCY=3 \
  -v /opt/mathesar/msar/static:/code/static \
  -v /opt/mathesar/msar/media:/code/.media \
  -v /opt/mathesar/msar/secrets:/code/.secrets \
  mathesar/mathesar:0.12.0

# 4) Caddy 反代(依赖容器名 mathesar_service 可解析,Caddyfile 内置在镜像中)
docker run -d --name mathesar_caddy --network mathesar-net \
  -p 8128:80 \
  -e DOMAIN_NAME=http://localhost \
  -v /opt/mathesar/msar/media:/code/.media \
  -v /opt/mathesar/msar/static:/code/static \
  -v /opt/mathesar/msar/caddy:/data \
  mathesar/mathesar-caddy:latest

生产环境仍建议用 Compose:depends_on 健康检查顺序、x-config 变量收拢、整栈一键升级都是 docker run 手工维护不了的。

九、常用运维命令

# 状态与资源
docker compose ps                                   # 三个服务的运行状态与健康检查结果
docker stats --no-stream mathesar_service mathesar_db   # 实测:service 约 285 MiB、db 约 84 MiB(空载)

# 日志
docker compose logs service --tail 50               # 应用日志(启动迁移、请求错误)
docker compose logs db --tail 50                    # PostgreSQL 日志

# 启停
docker compose stop service                         # 单独停应用
docker compose start service                        # 再启动
docker compose restart service                      # 重启应用
docker compose down                                 # 停止并移除三容器与网络(bind mount 数据保留)
docker compose up -d                                # 重新拉起

实测 docker compose down 回显:

 Container mathesar_service Removing
 Container mathesar_service Removed
 Container mathesar_db Stopping
 Container mathesar_db Stopped
 Container mathesar_db Removing
 Container mathesar_db Removed
 Network mathesar-0120-stack-net Removing
 Network mathesar-0120-stack-net Resource is still in use

⚠️ 最后一行 Resource is still in use 不是错误:如果按 4.5 接入了外部 PostgreSQL(--network mathesar-0120-stack-net),该网络被外部实例占用而无法删除,属预期现象;docker compose up -d 会原样复用这个网络,外部库连接不受影响(已实测验证)。

十、常见问题(FAQ)

Q1:宿主 80 端口被占用,怎么改入口端口? 只改 caddy-reverse-proxy 的 ports 一处即可,如 - "8128:80";DOMAIN_NAME 相应写成 http://<宿主IP>:8128。本指南全文即按 8128 实测。

Q2:SECRET_KEY 没设置,会有问题吗? 不会丢功能:应用启动时检测到 SECRET_KEY 为空,会自动生成随机密钥并写入挂载目录的 .secrets/secret_key.txt(实测文件存在,50 字节),重启复用同一文件。要显式管理时,在 compose 的 service 环境里传入 SECRET_KEY: ${SECRET_KEY} 并在宿主 .env 里赋值即可。

Q3:service 一直 restarting / healthy 起不来? 先看 docker compose logs service --tail 50。最常见原因是元数据库未就绪或连接参数错误:确认 POSTGRES_HOST 指向 db 服务的容器名(compose 内为 mathesar_db),且 db 容器已 (healthy)。应用自带 /healthz/ready/(实测返回 {"status": "ok"}),可用 curl http://localhost:8128/healthz/ready/ 快速分层定位是 Caddy、应用还是数据库的问题。

Q4:接入外部 PostgreSQL 时连不上? 外部库必须与 mathesar_service 网络可达:用 --network mathesar-0120-stack-net(或先把网络 connect 上去)并直接用容器名作 Host。若外部实例先于 compose 网络存在,用 docker network connect mathesar-0120-stack-net <外部实例名> 挂入即可。另外确认目标库角色有建 schema 权限(Mathesar 首次接入要装 msar 函数 schema)。

Q5:升级版本怎么做? 改 compose 中应用镜像 tag(如 mathesar/mathesar:0.12.0 → 目标版本),然后 docker compose up -d 重建 service;应用启动时会自动执行元数据库迁移(日志中的 Running migrations)。业务库侧 Mathesar 用 last_confirmed_sql_version/needs_upgrade_attention 字段追踪 SQL 层版本,如需对齐可调用 databases.upgrade_sql(见 API 篇)。升级前先备份 msar/ 整个目录。

Q6:忘了 admin 密码怎么办? 登录页提供密码重置入口(/auth/password_reset_confirm/ 路由,需要邮件后端);无邮件后端的内网环境,可临时开启 MATHESAR_DJANGO_ADMIN_ENABLED=true 进入 Django 原生后台改密,改完关闭。

十一、参考链接