Miniflux Docker Compose 部署实战:从基础单机到 Caddy/Traefik 自动 HTTPS

原创2026-10-13 19:16:001,977 阅读
文章标签:后端

Miniflux Docker Compose 部署实战:从基础单机到 Caddy/Traefik 自动 HTTPS

本指南以仓库 contrib/docker-compose 目录下的三份编排文件为核心,系统讲解如何用 Docker Compose 部署开源极简 RSS 阅读器 Miniflux。你将掌握基础版 basic.yml 的完整启动流程、DATABASE_URL / RUN_MIGRATIONS / CREATE_ADMIN 等关键环境变量的真实含义,以及如何通过 Caddy 或 Traefik 反向代理为 Miniflux 自动签发 HTTPS 证书;同时结合源码级证据,理解迁移、管理员初始化与健康检查背后的运行原理。

目录结构与三套方案概览

contrib/docker-compose 目录下提供了四份可直接使用的文件,其中三份 Compose 编排分别对应三种由浅入深的部署形态:

  • basic.yml:最简部署,Miniflux 直接通过宿主机端口对外提供服务,适用于内网或快速试用;
  • caddy.yml:以 Caddy 2 作为反向代理,配合 Caddyfile 自动申请与续期 HTTPS 证书;
  • traefik.yml:以 Traefik 2.3 作为反向代理,通过 Docker Provider 自动发现服务并签发证书。

三种方案共用同一套 PostgreSQL 数据库服务,启动命令仅需替换 -f 指定的文件名:

docker compose -f basic.yml up -d
docker compose -f caddy.yml up -d
docker compose -f traefik.yml up -d

前置条件:镜像与默认配置

所有 Compose 文件中的 Miniflux 镜像均使用变量 MINIFLUX_IMAGE,默认值为 miniflux/miniflux:latest:

image: ${MINIFLUX_IMAGE:-miniflux/miniflux:latest}

也就是说,无需修改文件即可直接使用官方镜像;如需固定版本或使用私有镜像仓库,可通过环境变量覆盖:

MINIFLUX_IMAGE=miniflux/miniflux:2.2.3 docker compose -f basic.yml up -d

镜像的构建方式同样沉淀在仓库中:packaging/docker/alpine/Dockerfile 使用多阶段构建,运行时基于 Alpine,内置 EXPOSE 8080 并以非 root 用户(UID 65534)运行;packaging/docker/distroless/Dockerfile 则提供 Distroless 变体,两者都在运行时通过 ENV LISTEN_ADDR=0.0.0.0:8080 绑定全部网卡的 8080 端口——这正是 Compose 文件中用 80:8080 或 expose 8080 映射的依据。若需自行构建镜像,Makefile 提供了 docker-image、docker-image-distroless 与 docker-images(多架构推送)目标。

方案一:basic.yml 基础部署

basic.yml 是官方提供的标准入门编排,完整内容如下:

services:
  miniflux:
    image: ${MINIFLUX_IMAGE:-miniflux/miniflux:latest}
    container_name: miniflux
    restart: always
    ports:
      - "80:8080"
    depends_on:
      db:
        condition: service_healthy
    environment:
      - DATABASE_URL=postgres://miniflux:secret@db/miniflux?sslmode=disable
      - RUN_MIGRATIONS=1
      - CREATE_ADMIN=1
      - ADMIN_USERNAME=admin
      - ADMIN_PASSWORD=test123
      - DEBUG=1
    # Optional health check:
    # healthcheck:
    #  test: ["CMD", "/usr/bin/miniflux", "-healthcheck", "auto"]
  db:
    image: postgres:latest
    container_name: postgres
    restart: always
    environment:
      - POSTGRES_USER=miniflux
      - POSTGRES_PASSWORD=secret
      - POSTGRES_DB=miniflux
    volumes:
      - miniflux-db:/var/lib/postgresql
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "miniflux"]
      interval: 10s
      start_period: 30s
volumes:
  miniflux-db:

启动顺序与依赖健康检查

depends_on 使用 condition: service_healthy,只有数据库通过健康检查后 Miniflux 才会启动,从根本上避免了“应用先于数据库就绪而崩溃退出”的竞态问题。数据库的健康检查由 pg_isready -U miniflux 承担,每 10 秒执行一次,并给予 30 秒启动宽限期(start_period)。

数据持久化方面,PostgreSQL 数据目录 /var/lib/postgresql 挂载到名为 miniflux-db 的命名卷上,容器重建后数据依然保留。container_name 被显式固定为 miniflux / postgres,便于日志查询(docker logs postgres)与容器间直接引用服务名。

环境变量逐项解析

环境变量 值 作用
DATABASE_URL postgres://miniflux:secret@db/miniflux?sslmode=disable PostgreSQL 连接串:用户 miniflux、密码 secret、主机 db(即 Compose 网络中的 db 服务名)、库名 miniflux,禁用 SSL 模式
RUN_MIGRATIONS 1 容器启动时自动执行数据库结构迁移
CREATE_ADMIN 1 自动创建初始管理员账号
ADMIN_USERNAME admin 初始管理员用户名
ADMIN_PASSWORD test123 初始管理员密码
DEBUG 1 输出调试日志,便于首次排错

关键变量的源码级原理

迁移机制。 internal/cli/cli.go 在启动守护进程前会检查 config.Opts.RunMigrations(),为真则调用 database.Migrate(db) 依次执行 internal/database/migrations.go 中按顺序追加的迁移函数,随后还会通过 database.IsSchemaUpToDate(db) 校验结构版本。如果关闭 RUN_MIGRATIONS 而数据库结构过旧,进程将直接报错退出。该选项默认关闭(见 internal/config/options.go 中 parsedBoolValue: false),因此 Compose 文件中显式设为 1 是首次部署的必要条件。

管理员创建。 CREATE_ADMIN=1 时,cli.go 会调用 createAdminUserFromEnvironmentVariables,从 ADMIN_USERNAME / ADMIN_PASSWORD 读取凭据创建管理员。internal/cli/create_admin.go 显示创建前会先检查用户名是否已存在,存在则直接跳过(并记录日志),因此该变量在容器重复重启时是幂等安全的。创建请求会经过 internal/validator 的校验并标记 IsAdmin: true。

配置解析。 internal/config/parser.go 将所有环境变量按 KEY=VALUE 格式逐行解析:未知键会被忽略(避免被无关环境变量干扰),布尔值支持 1/0/yes/no/true/false/on/off 等写法;postParsing 阶段还会校验 BASE_URL 必须为 http 或 https 协议。这正是 Compose 中各种配置项能以字符串形式传入并被正确转换的底层依据。

可选:为 Miniflux 容器添加健康检查

basic.yml 中保留了一段注释掉的健康检查配置,可自行启用:

    healthcheck:
      test: ["CMD", "/usr/bin/miniflux", "-healthcheck", "auto"]
      interval: 30s
      timeout: 5s
      start_period: 10s

-healthcheck auto 会依据运行配置自动拼接探活地址。internal/cli/health_check.go 的实现表明,auto 模式将请求发送到 http://<LISTEN_ADDR>/<BASE_PATH>/healthcheck,随后通过 HTTP 200 状态码判定健康;而 internal/http/server/healthcheck.go 中的就绪探针会真正 Ping 数据库,数据库不可达时返回 503。此外 internal/http/server/routes.go 还在根路径提供了 /liveness、/healthz、/readiness、/readyz 等标准端点,可被外部探针直接使用。

方案二:caddy.yml + Caddyfile 自动 HTTPS

caddy.yml 在基础方案之上增加了 Caddy 2 反向代理服务,将公网 80/443 流量转发给 Miniflux:

services:
  caddy:
    image: caddy:2
    container_name: caddy
    depends_on:
      - miniflux
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - $PWD/Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
      - caddy_config:/config
  miniflux:
    image: ${MINIFLUX_IMAGE:-miniflux/miniflux:latest}
    container_name: miniflux
    depends_on:
      db:
        condition: service_healthy
    environment:
      - DATABASE_URL=postgres://miniflux:secret@db/miniflux?sslmode=disable
      - RUN_MIGRATIONS=1
      - CREATE_ADMIN=1
      - ADMIN_USERNAME=admin
      - ADMIN_PASSWORD=test123
      - BASE_URL=https://miniflux.example.org
  db:
    image: postgres:latest
    container_name: postgres
    environment:
      - POSTGRES_USER=miniflux
      - POSTGRES_PASSWORD=secret
    volumes:
      - miniflux-db:/var/lib/postgresql
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "miniflux"]
      interval: 10s
      start_period: 30s
volumes:
  miniflux-db:
  caddy_data:
  caddy_config:

配套的 Caddyfile 极为简洁,仅两行:

miniflux.example.org
reverse_proxy miniflux:8080

Caddy 会自动为 miniflux.example.org 申请 Let's Encrypt 证书并透明续期,无需手动管理证书文件。注意这里 Miniflux 服务不再映射宿主机端口,仅暴露给 Compose 内部网络,由 Caddy 通过服务名 miniflux 与端口 8080 访问。caddy_data 与 caddy_config 两个卷用于持久化证书与 Caddy 配置,避免每次重建容器都重新签发证书。

必须同步设置 BASE_URL

与 basic.yml 相比,此方案为 Miniflux 增加了关键配置:

- BASE_URL=https://miniflux.example.org

Miniflux 需要知道自己对外暴露的公网地址,才能生成正确的绝对链接(如 feed 订阅地址、OPML 导出地址等)。该值的默认值是 http://localhost(internal/config/options.go),未配置时会生成无法被外部订阅的链接。请务必将 miniflux.example.org 替换为你自己的域名。

使用前将 Caddyfile 中的域名与 $PWD 路径对齐:volumes 中的 $PWD/Caddyfile 表示从当前执行 docker compose 的目录挂载 Caddyfile,因此请从 contrib/docker-compose 目录内运行启动命令,或在 -f 参数基础上同时用 --project-directory 指定正确的项目目录。

方案三:traefik.yml 自动 HTTPS

traefik.yml 使用 Traefik 2.3 作为入口,通过读取 Docker 套接字自动发现并路由服务:

services:
  traefik:
    image: "traefik:v2.3"
    container_name: traefik
    command:
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.myresolver.acme.tlschallenge=true"
      - "--certificatesresolvers.myresolver.acme.email=postmaster@example.com"
      - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
    depends_on:
      - miniflux
    ports:
      - "443:443"
    volumes:
      - "./letsencrypt:/letsencrypt"
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
  miniflux:
    image: ${MINIFLUX_IMAGE:-miniflux/miniflux:latest}
    container_name: miniflux
    depends_on:
      db:
        condition: service_healthy
    expose:
      - "8080"
    environment:
      - DATABASE_URL=postgres://miniflux:secret@db/miniflux?sslmode=disable
      - RUN_MIGRATIONS=1
      - CREATE_ADMIN=1
      - ADMIN_USERNAME=admin
      - ADMIN_PASSWORD=test123
      - BASE_URL=https://miniflux.example.org
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.miniflux.rule=Host(`miniflux.example.org`)"
      - "traefik.http.routers.miniflux.entrypoints=websecure"
      - "traefik.http.routers.miniflux.tls.certresolver=myresolver"
  db:
    image: postgres:latest
    container_name: postgres
    environment:
      - POSTGRES_USER=miniflux
      - POSTGRES_PASSWORD=secret
    volumes:
      - miniflux-db:/var/lib/postgresql
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "miniflux"]
      interval: 10s
      start_period: 30s
volumes:
  miniflux-db:

Traefik 侧的关键配置

command 中的参数完成三项工作:

  • --providers.docker=true 启用 Docker Provider;exposedbydefault=false 则要求每个服务显式打上 traefik.enable=true 标签才会被纳入路由,避免误暴露其他容器;
  • --entrypoints.websecure.address=:443 定义仅监听 443 的入口,因此宿主机只映射 443 端口;
  • --certificatesresolvers.myresolver.acme.* 配置 ACME 证书签发:使用 TLS Challenge(tlschallenge=true),绑定证书签发邮箱 postmaster@example.com(请替换为你自己的邮箱),证书存储到 /letsencrypt/acme.json,并通过 ./letsencrypt:/letsencrypt 卷持久化到宿主机。

Miniflux 侧的路由标签

Miniflux 服务通过 expose: "8080" 仅暴露内部端口,并依靠四个标签完成路由与证书绑定:

标签 作用
traefik.enable=true 允许该服务被 Docker Provider 纳入
traefik.http.routers.miniflux.rule=Host(\miniflux.example.org`)` 按域名匹配入站请求
traefik.http.routers.miniflux.entrypoints=websecure 路由绑定到 443 入口
traefik.http.routers.miniflux.tls.certresolver=myresolver 为该路由使用 myresolver 签发 TLS 证书

同样需要把 miniflux.example.org 与 postmaster@example.com 替换为真实域名与邮箱,并把 BASE_URL 指向同一域名。

三套方案的选型建议

对比项 basic.yml caddy.yml traefik.yml
对外端口 80(HTTP) 80 + 443 443
HTTPS 证书 无(如需 HTTPS 需自行配置 TLS) Caddy 自动签发与续期 Traefik ACME 自动签发
反向代理配置 无 Caddyfile 两行即可 依赖 Docker 标签
适用场景 内网、局域网、快速体验 公网单域名部署,配置最简 已有 Traefik 生态或多服务统一入口

生产化必须调整的安全项

上述 Compose 文件定位为“示例”,直接照搬用于生产存在明显风险,建议按如下清单调整:

  1. 修改默认口令:ADMIN_PASSWORD=test123 与数据库密码 secret 都是占位符,首次登录后应立即在界面中更换管理员密码,并将数据库凭据改为强随机值;更稳妥的做法是使用 Docker secrets 或外部密钥管理,仓库配置解析器也支持 DATABASE_URL_FILE 之类的 secret 文件形式(见 internal/config/options.go 中 secretFileType 的处理)。
  2. 关闭调试日志:basic.yml 中 DEBUG=1 便于首启排错,生产环境建议删除或设为 0。
  3. 配置正确的 BASE_URL:无论是否使用反代,都应将 BASE_URL 设为最终对外的完整地址(含协议与路径),否则订阅链接、OPML 导出等会指向错误地址。
  4. 固定镜像版本:将 miniflux/miniflux:latest 与 postgres:latest 替换为明确的版本号,避免无意间的破坏性升级。
  5. 绑定可用卷:确保 miniflux-db(以及 Caddy 的 caddy_data/caddy_config、Traefik 的 letsencrypt)落盘在持久化存储上,容器重建或宿主机重启后数据与证书不丢失。
  6. 数据库连接参数:示例使用 sslmode=disable,适用于 Compose 内部网络;若数据库与 Miniflux 不在同一受信网络,应改用 sslmode=require 或 verify-full 并配置证书。

常见问题速查

  • 容器启动即退出:通常是数据库尚未就绪或迁移失败。确认 db 服务健康后再观察 docker logs miniflux;迁移报错时可删除 miniflux-db 卷重新初始化(注意会清空数据)。
  • 登录提示用户不存在:CREATE_ADMIN 默认关闭,务必确认环境变量中 CREATE_ADMIN=1 且 ADMIN_USERNAME/ADMIN_PASSWORD 已设置;internal/cli/cli.go 只在检测到该选项时才创建管理员。
  • 反向代理下页面样式或链接异常:检查 BASE_URL 是否与代理入口域名完全一致,包括 https:// 前缀与可能的子路径;internal/config/parser.go 会从 BASE_URL 推导根地址与基础路径并用于生成链接。
  • 证书签发失败:确认域名已解析到服务器公网 IP,且 80/443 端口未被占用或防火墙拦截(TLS Challenge 依赖 443 连通)。
  • 健康检查显示 503:就绪探针会 Ping 数据库(internal/http/server/healthcheck.go),数据库不可达时返回 503,请检查 DATABASE_URL 与 db 服务状态。

总结

contrib/docker-compose 的三份编排文件覆盖了 Miniflux 容器化部署的完整路径:basic.yml 是最小可用集,适合理解 Miniflux + PostgreSQL 的启动与初始化模型;caddy.yml 以两行 Caddyfile 换来开箱即用的自动 HTTPS;traefik.yml 则展示了基于 Docker Provider 与标签路由的网关式接入。配合仓库源码中对迁移、管理员创建、健康检查与配置解析的实现,你可以快速定位问题、按生产标准加固配置,并在此骨架之上按需扩展。

登录后查看全文
v2