build(deploy): containerize the frontend and add it to docker compose - #187
Merged
huyanxius merged 6 commits intoAug 11, 2026
Merged
Conversation
The frontend ships no container image, so the deployment described in docker-compose.yml cannot serve it next to the backend. Add a multi-stage Dockerfile that builds with Node and ships only dist on nginx, together with an nginx config providing SPA fallback and an /api reverse proxy to the backend service. The image serves pages and API calls from one origin, so the deployment needs no CORS configuration at all.
Compose orchestrates Redis, PostgreSQL and the backend, leaving the frontend outside the single-server deployment. Add a frontend service building from ./frontend on the shared network, publishing WINDUP_WEB_PORT, and passing VITE_API_BASE_URL as a build argument since Vite bakes it at build time. One compose command now brings up the whole stack, and the example env file documents both new variables.
The README covers local development only and says nothing about how the app reaches the backend once containerized. Describe the compose workflow, the nginx reverse proxy, and why VITE_API_BASE_URL cannot be injected at runtime. Readers can deploy without rediscovering the build-time constraint, and the Vercel path is stated as unaffected.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
The nginx proxy inherits a 1 MB default request body limit, so images sent to /media/upload are rejected with 413 before FastAPI receives them. Set client_max_body_size to 20 MB on the /api/ location, leaving the static routes untouched. Uploads up to 20 MB now reach the backend, while a 25 MB request is still refused at the proxy.
Contributor
方案调整建议宿主机已在跑 nginx 负责静态资源服务和 建议:容器只做构建,产物通过 volume 挂到宿主机,由宿主机 nginx 直接服务。
更新时 |
Collaborator
Author
收到,正在改 |
The server already owns static serving and API proxying. Make the Node container write Vite output into the mounted web root and exit. Deployments no longer run or expose a second nginx instance.
The previous guide still described the removed container nginx and web port. Document the host web root, one-shot build command, and API proxy ownership. Operators can now update frontend assets without expecting a long-running container.
Collaborator
Author
@xiaocheny214 已按建议调整,前端容器现在只负责构建,产物由宿主机 nginx 直接服务,麻烦再帮忙看一下 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
前端补上容器化部署:新增前端镜像,并作为第四个服务接入现有的
docker-compose.yml。服务器上docker compose up -d --build一条命令即可连前端一起起来,不再依赖 Vercel。Why
#162 把 Redis、PostgreSQL 和后端编排进了 compose,前端不在其中。前端此前只有 Vercel 一条部署路径(
frontend/vercel.json),服务器上没有它的产物,整套系统在一台机器上起不完整。次要动机是跨域。前端与后端不同源时,浏览器对非简单请求先发预检,后端需维护来源白名单,#139 与尚未关闭的 #184 都出在这条链路上。容器内反代让两者同源,这条链路不再被触发。
Changes
dist/,产物 22 MB。WINDUP_WEB_PORT(默认 8080)访问,子路由直接访问不再 404。/api/,由容器内 nginx 转发至backend:8000,后端无需为前端配置 CORS 来源。.env.example增加WINDUP_WEB_PORT与VITE_API_BASE_URL,frontend/README.md补容器部署说明。Implementation
后端地址在构建期确定。
VITE_前缀的变量由vite build写入产物,运行期注入环境变量对已构建的 JS 无效,因此它放在 compose 的build.args而非environment。默认值/api是相对路径,镜像不绑定域名,同一产物可跨环境复用;要指向外部后端则构建期传--build-arg VITE_API_BASE_URL=…,并同步配置后端的WINDUP_CORS_ORIGINS。反代按请求解析主机名。直写
proxy_pass http://backend:8000/时 nginx 只在启动时解析一次,backend 重建换 IP 后前端会持续 502,且启动时解析失败会导致 nginx 起不来。改用resolver 127.0.0.11加变量形式规避这两点;变量形式下 nginx 不再自动剥前缀,故配合rewrite ^/api/(.*)$ /$1 break,query string 由 rewrite 保留。前缀剥离对齐后端现有路由。
/projects、/characters、/users均挂在根路径,/api/projects需落为backend:8000/projects。后端若引入路由前缀,此处要同步调整。depends_on只等 backend 启动、不等 healthy,保证后端异常时前端静态页仍可访问。缓存分两档:
/assets/的文件名带内容 hash,给长缓存并标 immutable;index.html显式 no-cache,避免发版后旧 html 引用已删除的资源导致白屏。Verification
npm run format:check,全部文件格式正确npm run lint,oxlint 无告警npm run typecheck,通过npm run test,27 个文件 191 条用例全过docker build ./frontend成功,镜像内执行的是tsc -b && vite build容器级验证以一个返回
$request_uri的 nginx 桩容器充当 backend,与前端容器同处一个 user-defined 网络:/api/projects502/api/projects/projects,前缀已剥/api/projects?page=2/projects?page=2,query 保留/projects直接访问index.htmlindex.html为 no-cache,assets/*.js为 max-age=31536000, immutablefunction _r(e=`/api`)/api/projects仍然通健康探针最初写作
wget http://localhost/,容器始终 unhealthy:busybox 的 wget 优先解析::1,而 nginx 只listen 80。已改为127.0.0.1并复验。整栈四容器未在本机跑通。后端镜像构建成功,但本机存在一个 2026-07-31 由手工
docker run创建的同名容器windup-postgres(非 compose 创建,挂载命名卷windup-postgres-data),占用容器名导致创建冲突,未予清理。改以docker compose up -d --no-deps frontend验证服务定义:容器创建正常,端口映射0.0.0.0:8080->80,首页与子路由均 200。四容器同时 healthy 待在服务器上确认。Screenshots
两张均取自容器(宿主机 8080 端口)。本 PR 不改界面代码,因此只提供 After。
右图为直接访问
/projects:nginx 回退到index.html,前端路由接管后按 #178 的登录守卫跳转至/?account=login&returnTo=%2Fprojects。没有回退则此处为 404。Scope
WINDUP_WEB_PORT);vercel.json不动,Vercel 路径照旧可用;frontend-ci.yml不动;业务代码与shared/api实现不动;fix(backend): 放行受保护接口的 CORS 预检请求 #184 的后端预检问题不在本 PR 修。Related Issues
Closes #185
Refs #162
Refs #184