Reflex 生产环境部署实战:基于 Docker Compose + Caddy 自动 TLS 的单机部署指南
2026/9/11 12:14:52 网站建设 项目流程

Reflex 生产环境部署实战:基于 Docker Compose + Caddy 自动 TLS 的单机部署指南

【免费下载链接】reflex🕸️ Web apps in pure Python 🐍项目地址: https://gitcode.com/GitHub_Trending/re/reflex

本篇指南以 Reflex 官方仓库中的 production-compose 示例 为核心,完整讲解如何在一台独立 VPS 上,用 Docker Compose 编排 Caddy 反向代理与 Reflex 后端服务,实现「静态前端由 Caddy 直出、后端仅跑 Python 服务、HTTPS 证书自动签发」的生产级单机部署。读完本文,你将掌握该示例的全部构建细节、Caddyfile 路由配置、数据持久化方案,以及如何叠加 Postgres、Redis 与管理工具组成更健壮的部署栈。

一、方案概览:为何选择 production-compose

Reflex 官方在 docker-example 目录下提供了多种 Docker 部署范式,production-compose是其中面向「独立 VPS、单应用托管」场景的完整栈方案。它与其他方案的本质区别在于:

  • 前端静态化:应用镜像在构建阶段通过reflex export --frontend-only将前端导出为静态文件,交由 Caddy 直接托管,运行期不再需要 Node.js;
  • 自动 TLS:Caddy 充当 Web 服务器与反向代理,为localhost或环境变量DOMAIN指定的域名自动申请并续期 HTTPS 证书;
  • 单栈编排:一个compose.yaml即可拉起 Web 服务器与后端,配合覆盖文件可追加 Postgres、Redis 与管理工具。

从架构看,这是「静态资源 + 动态接口分离」的经典模式:浏览器请求静态页面时由 Caddy 直接返回,只有后端 API 类请求(事件处理、上传、健康检查等)才会被代理转发到应用容器。由于后端镜像不包含 Node.js 运行时,这种部署方式占用内存更少、性能更佳——这是原文档明确指出的优势,也是选择该方案的核心动机。

二、镜像构建:两阶段 Dockerfile 拆解

production-compose 的核心构建逻辑位于根目录 Dockerfile,采用标准的多阶段构建,将「构建产物」与「运行环境」彻底分离。

阶段一:init —— 导出静态前端

基础镜像为python:3.13,首先安装uv以加速 Python 依赖引导,然后将项目上下文复制到/app

FROM python:3.13 as init ARG uv=/root/.local/bin/uv ADD --chmod=755 https://astral.sh/uv/install.sh /install.sh RUN /install.sh && rm /install.sh WORKDIR /app COPY . . RUN mkdir -p /app/data /app/uploaded_files

随后在虚拟环境中安装依赖,并依次执行 Reflex 的初始化与前端导出:

ENV VIRTUAL_ENV=/app/.venv ENV PATH="$VIRTUAL_ENV/bin:$PATH" RUN $uv venv RUN $uv pip install -r requirements.txt RUN reflex init RUN reflex export --frontend-only --no-zip

这里的reflex export --frontend-only --no-zip是关键一步:--frontend-only只导出前端产物(后端不参与静态导出),--no-zip表示直接输出目录而非压缩包,导出结果位于/app/.web/build/client。为节省后端镜像体积,阶段末尾将静态文件移出.web目录后重建:

RUN mv .web/build/client /tmp/client RUN rm -rf .web && mkdir -p .web/build RUN mv /tmp/client .web/build/client

阶段二:slim —— 精简运行镜像

最终镜像基于python:3.13-slim,只携带虚拟环境与静态产物:

FROM python:3.13-slim WORKDIR /app RUN adduser --disabled-password --home /app reflex COPY --chown=reflex --from=init /app /app RUN apt-get update -y && apt-get install -y libpq-dev && rm -rf /var/lib/apt/lists/* USER reflex ENV PATH="/app/.venv/bin:$PATH" PYTHONUNBUFFERED=1

几个值得注意的实现细节:

  • 以非 root 用户reflex运行,符合最小权限原则;
  • libpq-dev是为psycopg(Postgres 驱动)准备的编译依赖,注释明确说明「如果不使用 Postgres 可以跳过」;
  • STOPSIGNAL SIGKILL用于规避 Reflex 后端暂未正确传递 SIGTERM 的问题;
  • 启动命令在容器入口统一处理数据库迁移,再以生产模式仅启动后端:
CMD [ -d alembic ] && reflex db migrate; \ exec reflex run --env prod --backend-only

--backend-only意味着该容器不负责提供任何前端页面,只运行后端事件服务,前端完全交给 Caddy。reflex db migrate仅在项目存在alembic目录(即启用了数据库迁移)时才执行,保证每次启动前 schema 与代码一致。

三、Web 服务器:Caddy 的自动 TLS 与反向代理

Caddy 镜像

Caddy.Dockerfile 非常简单——基于官方caddy镜像,将构建产物(local/reflex-app镜像内的静态前端)复制到/srv,并注入 Caddyfile 配置:

FROM library/caddy COPY --from=local/reflex-app /app/.web/build/client /srv ADD Caddyfile /etc/caddy/Caddyfile

注意这里的--from=local/reflex-app引用的是 compose 中构建出的本地镜像名(见下文 compose 的image: local/reflex-app),两阶段镜像间通过该名称衔接。

Caddyfile 路由设计

Caddyfile 是整条请求链路的枢纽,全文如下:

{$DOMAIN} encode gzip @backend_routes path /_event/* /ping /_upload /_upload/* handle @backend_routes { reverse_proxy app:8000 } root * /srv route { try_files {path} {path}/ /404.html file_server }

逐行解读:

  • {$DOMAIN}:站点地址由环境变量注入。Caddy 会根据该值自动申请证书,localhost则走本地自签证书;
  • encode gzip:对响应启用 gzip 压缩;
  • @backend_routes定义了一组「必须转发给后端」的路径匹配器,包含/_event/*(Reflex 事件处理端点)、/ping(健康检查)、/_upload/_upload/*(文件上传端点)。命中后由reverse_proxy app:8000转发到 compose 服务名为app的容器 8000 端口(Reflex 后端默认端口);
  • root * /srv指定静态资源根目录;
  • route块内try_files先尝试精确路径、再尝试目录索引,兜底返回404.html,最后file_server提供静态文件服务。

原文档特别提示:如果应用使用了额外的后端 API 路由,需要同步把它们追加到@backend_routes路径匹配器中,否则这些请求会被 Caddy 当作静态资源处理而得不到正确的后端响应。这是自定义该方案时最容易被忽略的一步。

四、Compose 编排:基础栈与三种启动方式

基础 compose.yaml

compose.yaml 定义了两个核心服务:

服务镜像职责关键配置
applocal/reflex-appReflex 后端REFLEX_DB_URL: sqlite:///data/reflex.db,挂载db-dataupload-data
webserverCaddyTLS 终止 + 静态托管 + 反向代理暴露443/80端口,挂载caddy-data卷,depends_on: app

关键点:

  • REFLEX_DB_URL默认使用 SQLite,数据库文件落在/app/data(对应命名卷db-data);
  • DOMAIN: ${DOMAIN:-localhost}:域名由宿主环境变量注入,未设置时回退为localhost——这正是原文档强调「如果不提供 DOMAIN,服务将默认 localhost」的代码依据;
  • 80端口保留用于 ACME HTTP 质询(证书签发验证);
  • 三个命名卷分别持久化数据库(db-data)、上传文件(upload-data)与 TLS 证书(caddy-data)。证书卷尤其重要:若不持久化,Caddy 每次重建容器都要重新签发证书,可能触发速率限制。

构建与启动命令

构建时必须传入DOMAIN(注意不要带http://https://前缀,Caddy 会强制使用 HTTPS):

DOMAIN=example.com docker compose build

该命令会同时构建app(默认 Dockerfile)与webserver(Caddy.Dockerfile)两个服务。随后启动:

DOMAIN=example.com docker compose up

应用即在指定域名以 HTTPS 提供访问。原文档提醒:证书签发是自动进行的,首次可能耗时几分钟,期间请耐心等待或观察 Caddy 日志。

数据持久化清单

整个栈共使用 4 个命名卷,职责划分如下:

卷名挂载位置持久化内容
db-data/app/dataSQLite 数据库文件
upload-data/app/uploaded_files用户上传文件
caddy-data/root/.caddyTLS 密钥与证书
postgres-data/var/lib/postgresql/dataPostgres 数据(compose.prod.yaml 引入)

五、健壮化部署:叠加 Postgres 与 Redis

原文档指出,若要支撑更大流量、让后端以多 worker 运行,应使用 compose.prod.yaml 覆盖文件,它额外引入了 Postgres 与 Redis:

DOMAIN=example.com docker compose -f compose.yaml -f compose.prod.yaml up -d

覆盖文件的核心改动:

services: db: image: postgres restart: always environment: POSTGRES_PASSWORD: secret redis: image: redis restart: always app: environment: REFLEX_DB_URL: postgresql+psycopg://postgres:secret@db/postgres REFLEX_REDIS_URL: redis://redis:6379 depends_on: - db - redis

两个环境变量的语义可以从源码得到印证:

  • REFLEX_DB_URL对应 Reflex 配置中的db_url(见 reflex/model.py 中url or conf.db_url的取值逻辑),此处切换为postgresql+psycopg驱动;
  • REFLEX_REDIS_URL对应redis_url配置,reflex/utils/prerequisites.py 中的parse_redis_url()明确校验该值必须以前缀redis://rediss://unix://开头——redis://redis:6379符合规范。Redis 在后端启用多 worker 时承担状态共享与缓存职责。

切换数据库后,Postgres 使用独立的postgres-data命名卷持久化数据(原文档特别说明这一点)。注意POSTGRES_PASSWORD: secret是示例值,真实生产环境务必替换为强密码,并建议通过 compose 的.env文件或密钥管理机制注入。

六、管理工具:按需启用的运维辅助栈

compose.tools.yaml 提供了两个图形化管理工具,需与 prod 覆盖文件叠加使用:

DOMAIN=example.com docker compose -f compose.yaml -f compose.prod.yaml -f compose.tools.yaml up -d
服务工具访问地址用途
adminerAdminerhttp://localhost:8080图形化数据库管理
redis-commanderRedis Commanderhttp://localhost:8081Redis 缓存浏览器

redis-commander通过REDIS_HOSTS=local:redis:6379指定要连接的 Redis 实例。原文档明确建议:这些服务仅在需要时临时拉起,不推荐长期部署——它们面向运维排查场景,常驻运行只会增加攻击面与资源占用。

七、自定义要点与部署检查清单

综合原文档与源码实现,部署或改造该方案时应重点检查以下事项:

  1. 追加后端路由:应用新增了自定义 API 端点时,务必同步更新 Caddyfile 中的@backend_routes匹配器;
  2. 环境变量一致性DOMAIN在构建与启动时都应传入(虽然 Caddyfile 的{$DOMAIN}在容器运行期读取,但保持一致的部署习惯可避免混淆);域名不带协议前缀;
  3. 数据库迁移:镜像启动命令会检测alembic目录自动执行reflex db migrate;更换 Postgres 后需确认psycopg依赖与libpq-dev已就位;
  4. Redis URL 前缀REFLEX_REDIS_URL仅接受redis://rediss://unix://三种前缀(源码校验),填错将导致启动期解析失败;
  5. 证书续期caddy-data卷务必持久化,否则重建容器会触发证书重新签发;
  6. 安全基线:将示例中的 Postgres 密码、管理工具暴露端口替换为符合生产要求的配置,管理工具仅在需要时启用。

八、总结

production-compose示例为 Reflex 应用提供了一套开箱即用、可渐进增强的单机生产部署方案:两阶段镜像构建保证运行镜像轻量无 Node.js,Caddy 一站式解决静态托管、反向代理与自动 HTTPS,compose 覆盖文件机制让「基础栈 → 高可用栈 → 运维栈」的演进只差一条命令。无论是快速上线一个个人项目,还是作为更大规模部署的参照样板,这份配置都值得直接复用并按上述清单定制。

如需对比其他部署形态(单端口、双端口、平台托管),可继续阅读仓库中的 docker-example 总览 与 production-one-port、simple-two-port 等相邻示例。

【免费下载链接】reflex🕸️ Web apps in pure Python 🐍项目地址: https://gitcode.com/GitHub_Trending/re/reflex

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询