Reflex 生产部署实战:基于 Caddy 单端口静态导出与多阶段构建(production-one-port)
Reflex 生产部署实战基于 Caddy 单端口静态导出与多阶段构建production-one-port【免费下载链接】reflex️ Web apps in pure Python 项目地址: https://gitcode.com/GitHub_Trending/re/reflex本指南围绕仓库 docker-example/production-one-port 示例展开讲解如何将 Reflex 应用以生产模式打包进单个容器通过一个 HTTP 端口对外提供服务Caddy 负责静态托管前端导出产物并把后端 API 请求反代给 Reflex 后端容器内同时运行本地 Redis 保存用户状态。读完本文你将掌握该 Dockerfile 的每一层构建意图、Caddyfile 的路由规则以及如何在 Render、Heroku 等单端口应用平台上正确构建、运行和持久化该容器。单端口部署的整体架构production-one-port 是一个「单容器、单端口」的生产部署方案。整个容器对外只暴露一个端口8080对应$PORT——由 Caddy 服务器监听它一方面把构建期导出的前端静态文件托管出去另一方面将后端相关请求反代给容器内的 Reflex 后端进程。此外容器内部还会启动一个本地 Redis 服务器用于存储每个用户的会话状态通过环境变量REFLEX_REDIS_URLredis://localhost指向本地实例。前端采用静态导出static export而非运行 Vite 开发服务器因此整体资源占用更低特别适合内存受限的部署环境。与 simple-one-port 的区别从概念上讲production-one-port 与 simple-one-port 示例非常相似都使用 Caddy 单端口 本地 Redis两者的差异体现在镜像构建方式上特性simple-one-portproduction-one-portPython 依赖层缓存无有单独 COPY requirements.txt 先安装Reflex/Node 依赖层缓存无有先reflex init再预装 bun 依赖构建方式单阶段多阶段builder slim 最终镜像最终镜像体积较大更小仅保留运行所需文件正因为这两点优化production-one-port 更适合内存受限、对镜像体积敏感的生产环境。构建与运行构建镜像在包含requirements.txt、rxconfig.py和应用源码的项目根目录执行docker build -t reflex-production-one-port .构建时可以通过--build-arg覆盖 Dockerfile 中定义的构建参数docker build \ --build-arg PORT10000 \ --build-arg API_URLhttps://myapp.example.com \ -t reflex-production-one-port .PORT默认8080。如果目标平台有特殊端口要求例如 Render 期望应用监听10000端口在此指定。API_URL默认留空。仅用于本地直连场景当使用 TLS 时前端 API 地址被假定与前端地址相同无需单独设置。运行容器docker run -p 8080:8080 reflex-production-one-port注意该容器没有任何持久化停止后所有数据都会丢失。如果需要保留数据库与上传文件请使用 bind mount 或 named volume 挂载对应的database与uploaded_files目录例如docker run -p 8080:8080 \ -v reflex-data:/app/database \ -v reflex-uploads:/app/uploaded_files \ reflex-production-one-port使用场景该容器应当部署在已有的负载均衡器或反向代理之后由它们负责 TLS 终止非常适合 Render、Heroku 这类只支持暴露单一端口、且不希望容器内常驻 node 进程的简单应用平台。Dockerfile 逐层解析多阶段构建与层缓存Dockerfile 是整个方案的核心分为 builder 与最终运行镜像两个阶段。阶段一builderpython:3.13准备虚拟环境与目录创建/app/.web目录并在/app/.venv中建立 Python 虚拟环境将其加入PATH。安装 Python 依赖并利用层缓存先单独COPY requirements.txt .并执行pip install -r requirements.txt。由于 Docker 的层缓存机制只要requirements.txt未变化这一层就会被复用避免每次构建都重新安装依赖。仓库根目录 README.md 也提醒务必保证requirements.txt始终包含reflex包并保持最新。初始化 Reflex 并预装前端依赖COPY rxconfig.py ./后执行reflex init生成项目骨架随后把本地已有的*.web/bun.lockb与*.web/package.json复制进容器并用 Reflex 自带的 bun 执行bun install --frozen-lockfile预装锁定的前端依赖同样受益于层缓存。导出静态前端复制完整项目上下文后执行reflex export --loglevel debug --frontend-only --no-zip该命令只导出前端--frontend-only、不打包成 zip--no-zip产物位于.web/build/client随后被移动到/srv并删除.web目录以缩小最终镜像。在源码层面reflex export由 reflex/reflex.py 实现它会根据REFLEX_API_URL此处通过REFLEX_API_URL${API_URL:-http://localhost:$PORT}计算在前端产物中写入正确的 API 地址。阶段二最终镜像python:3.13-slim通过 apt 安装caddy与redis-server两个运行时组件并清理 apt 缓存设置运行环境变量PORT、REFLEX_API_URL默认http://localhost:$PORT、REFLEX_REDIS_URLredis://localhost、PYTHONUNBUFFERED1仅从 builder 阶段拷贝/app与/srv两个目录其余构建期文件一律丢弃STOPSIGNAL SIGKILL在 Reflex 后端尚未正确传递 SIGTERM 之前用 SIGKILL 保证容器能及时停止EXPOSE $PORT声明对外端口。容器启动命令CMD[ -d alembic ] reflex db migrate; \ caddy start \ redis-server --daemonize yes \ exec reflex run --env prod --backend-only启动序列依次完成若存在alembic目录先执行reflex db migrate应用数据库迁移对应源码 reflex/reflex.py 中的migrate命令后台启动 Caddycaddy start以守护进程方式启动 Redisredis-server --daemonize yes最后以exec方式运行reflex run --env prod --backend-only即只启动生产模式后端不再运行前端服务器——前端由 Caddy 静态托管。Caddyfile前端静态托管与后端反向代理Caddyfile 定义单端口上的全部路由逻辑:{$PORT} encode gzip backend_routes path /_event/* /ping /_upload /_upload/* handle backend_routes { reverse_proxy localhost:8000 } root * /srv route { try_files {path} {path}/ /404.html file_server }逐行说明:{$PORT}监听$PORT环境变量指定的端口encode gzip对响应启用 gzip 压缩backend_routes path /_event/* /ping /_upload /_upload/*定义后端路由匹配器——WebSocket 事件通道/_event/*、健康检查/ping、文件上传/_upload相关路径handle backend_routes { reverse_proxy localhost:8000 }将上述请求反代到容器内的 Reflex 后端默认端口 8000root * /srv静态文件根目录为构建阶段导出的前端产物route { try_files {path} {path}/ /404.html; file_server }优先按路径查找静态文件找不到时回退到/404.html保证 SPA 路由可用最后由file_server提供静态文件服务。Redis 与后端配置要点容器通过环境变量REFLEX_REDIS_URLredis://localhost指定后端状态存储。仓库源码 reflex/utils/prerequisites.py 中的parse_redis_url会对该值做校验必须以redis://、rediss://或unix://开头否则抛出ValueError。这也意味着在本示例的基础上你可以轻松将 Redis 指向远程实例如rediss://加密连接或外部托管服务而不改变容器内其他结构。关于REFLEX_API_URL当容器被部署在负载均衡/边缘网关之后并启用 TLS 时前端访问后端的地址与前端自身地址一致因此无需单独配置API_URL只有当需要本地直连、前后端地址不同时才需要显式传入该构建参数。生产部署注意事项小结持久化是必须自行解决的问题容器本身无状态务必用 bind mount 或 named volume 保存databaseSQLite 数据库与uploaded_files用户上传文件TLS 由边缘负责Caddy 在容器内以 HTTP 监听$PORTHTTPS 证书与终止应交给前置负载均衡器或平台边缘端口按平台调整Render 期望PORT10000Heroku 等其他平台可能不同构建时通过--build-arg PORT...传入即可Caddyfile 与EXPOSE都会随之生效前端是静态导出容器内不运行 node/Vite 进程内存占用更小这正是该方案优于两端口方案参考 simple-two-port的核心原因也是它被推荐用于内存受限环境的价值所在。【免费下载链接】reflex️ Web apps in pure Python 项目地址: https://gitcode.com/GitHub_Trending/re/reflex创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考