feat: publish frontend Docker image to GHCR (issue #239)#240
Conversation
- Add docker-publish-frontend.yml workflow mirroring the backend one (image github-stars-manager-frontend, multi-arch amd64/arm64, latest/semver/sha tags) - Make backend proxy upstream configurable via BACKEND_HOST env (default backend:3000) using nginx.conf.template + envsubst - Add .dockerignore to slim the frontend build context - Switch docker-compose frontend to the published GHCR image, keeping a local build option - Update DOCKER.md / README docs for the frontend image - Remove dead nginx.conf (superseded by nginx.conf.template)
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughThe frontend now publishes multi-architecture Docker images to GHCR, uses tagged prebuilt images in Compose, configures Nginx with ChangesFrontend GHCR deployment
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant DockerCompose
participant GHCR
participant FrontendContainer
participant BackendService
DockerCompose->>GHCR: Pull tagged frontend image
GHCR-->>DockerCompose: Return image
DockerCompose->>FrontendContainer: Start with BACKEND_HOST
FrontendContainer->>FrontendContainer: Render Nginx configuration
FrontendContainer->>BackendService: Proxy /api/ requests
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces pre-built frontend Docker images published to GHCR, updates the documentation and docker-compose configuration to support them, and makes the Nginx backend API proxy host configurable via a BACKEND_HOST environment variable using envsubst. Feedback on these changes highlights two issues in nginx.conf.template: first, using a variable in proxy_pass forces runtime DNS resolution which can break in non-Docker environments, so directly substituting BACKEND_HOST into proxy_pass is recommended; second, there is a CORS specification violation where Access-Control-Allow-Origin is set to '*' while Access-Control-Allow-Credentials is set to 'true'.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| set $backend_upstream ${BACKEND_HOST}; | ||
| proxy_pass http://$backend_upstream; |
There was a problem hiding this comment.
Using a variable in proxy_pass (e.g., proxy_pass http://$backend_upstream;) forces Nginx to resolve the hostname at runtime, which requires a resolver directive. Currently, nginx.conf.template hardcodes resolver 127.0.0.11; (the Docker internal DNS). This breaks DNS resolution in non-Docker environments like Kubernetes, AWS ECS, or custom networks where 127.0.0.11 is not the DNS server.
By directly substituting the BACKEND_HOST into proxy_pass (i.e., proxy_pass http://${BACKEND_HOST};), Nginx will resolve the hostname at startup using the system's standard resolver (from /etc/resolv.conf), making the image fully compatible with Kubernetes and other platforms without needing a hardcoded resolver directive.
Note: Once this is applied, you can also safely remove or comment out the resolver directive on line 8.
proxy_pass http://${BACKEND_HOST};
| add_header 'Access-Control-Allow-Origin' '*' always; | ||
| add_header 'Access-Control-Allow-Credentials' 'true' always; |
There was a problem hiding this comment.
According to the CORS specification, the Access-Control-Allow-Origin header cannot be set to the wildcard * when Access-Control-Allow-Credentials is set to true. If a client attempts to make a credentialed request (e.g., including cookies or authorization headers) to these static assets, the browser will block the request and throw a CORS error.
Since these are static assets served by Nginx, credentials are not required for CORS. Removing the Access-Control-Allow-Credentials header resolves this conflict and ensures standard-compliant CORS behavior.
add_header 'Access-Control-Allow-Origin' '*' always;
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
.dockerignore (1)
20-20: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winAdd
.envto.dockerignoreto prevent secret leakage.
.envfiles often contain secrets (API keys, encryption keys). If the Dockerfile build stage usesCOPY . ., these would be included in the build context sent to the Docker daemon.🔒 Proposed addition
*.md .DS_Store +.env +.env.*🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.dockerignore at line 20, Add .env to the ignore patterns in .dockerignore so environment files containing secrets are excluded from the Docker build context, including builds that use COPY . ...github/workflows/docker-publish-frontend.yml (1)
9-13: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd concurrency control to cancel redundant builds.
Multiple pushes to
mainin quick succession will trigger concurrent builds, wasting CI minutes and potentially causing GHA cache conflicts. Adding aconcurrencyblock cancels superseded runs.♻️ Proposed addition (top-level, after `env:`)
env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository_owner }}/github-stars-manager-frontend + +concurrency: + group: docker-publish-frontend-${{ github.ref }} + cancel-in-progress: true jobs:🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/docker-publish-frontend.yml around lines 9 - 13, Add a top-level concurrency configuration after the env block in the workflow, using a stable group identifier for this workflow and enabling cancellation of in-progress runs so newer pushes supersede redundant builds.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/docker-publish-frontend.yml:
- Around line 44-52: Update the semver tag entries in the workflow’s tags
configuration to include the “v” prefix, so version tags such as v0.6.2, v0.6,
and v0 are published and match the documented FRONTEND_IMAGE_TAG value. Preserve
the existing latest and SHA tag behavior.
In `@docker-compose.yml`:
- Around line 12-13: Update the BACKEND_HOST entry in the Compose service
environment to use Docker Compose variable substitution with a backend:3000
default, matching the existing FRONTEND_IMAGE_TAG and BACKEND_IMAGE_TAG pattern
so .env overrides are honored.
In `@DOCKER.md`:
- Around line 155-158: Update the local build section’s `docker run` command to
pass `BACKEND_HOST=host.docker.internal:3000`, matching the preceding pre-built
image example so standalone containers can reach the host backend.
---
Nitpick comments:
In @.dockerignore:
- Line 20: Add .env to the ignore patterns in .dockerignore so environment files
containing secrets are excluded from the Docker build context, including builds
that use COPY . ..
In @.github/workflows/docker-publish-frontend.yml:
- Around line 9-13: Add a top-level concurrency configuration after the env
block in the workflow, using a stable group identifier for this workflow and
enabling cancellation of in-progress runs so newer pushes supersede redundant
builds.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: d0625513-58b2-4df0-99da-7d5f38a53fe7
📒 Files selected for processing (8)
.dockerignore.github/workflows/docker-publish-frontend.ymlDOCKER.mdDockerfileREADME.mdREADME_zh.mddocker-compose.ymlnginx.conf.template
- nginx.conf.template: use static proxy_pass http://${BACKEND_HOST} (substituted
at container start) instead of a runtime variable, and drop the hardcoded
Docker-only resolver so the image works on Kubernetes/ECS too (gemini HIGH)
- nginx.conf.template: remove invalid Access-Control-Allow-Credentials:true
alongside Access-Control-Allow-Origin:* (gemini MEDIUM)
- docker-compose.yml: BACKEND_HOST now uses ${BACKEND_HOST:-backend:3000} so
.env overrides are honored (coderabbitai MAJOR)
- Docs: use unprefixed semver tags (0.6.2) consistent with the backend image
(coderabbitai MAJOR); add -e BACKEND_HOST to the local-build docker run
example (coderabbitai MINOR)
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
nginx.conf.template (2)
5-8: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy liftPreserve backend DNS re-resolution.
BACKEND_HOSTis rendered into a literalproxy_passtarget at startup, so Nginx resolves it once and will keep using that IP until reload. If the backend container is recreated or the hostname changes,/api/can start returning 502s. Add a runtime resolver or reload the frontend when the backend address changes.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@nginx.conf.template` around lines 5 - 8, Update the nginx http configuration around the mime-type and default-type directives to preserve runtime DNS re-resolution for the backend used by the rendered proxy_pass target. Add an appropriate resolver configuration, or otherwise ensure the frontend reloads when BACKEND_HOST changes, so recreated backend containers do not leave proxy requests targeting a stale IP.
35-40: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winForward the upstream host.
Host $hostsends the frontend hostname to the backend;$proxy_hostmatches the configuredBACKEND_HOSTand avoids host-based routing mismatches.Proposed fix
- proxy_set_header Host $host; + proxy_set_header Host $proxy_host;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@nginx.conf.template` around lines 35 - 40, Update the proxy_set_header Host directive in the proxy_pass configuration to forward $proxy_host instead of $host, ensuring the backend receives the configured BACKEND_HOST while leaving the other forwarded headers unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@nginx.conf.template`:
- Around line 5-8: Update the nginx http configuration around the mime-type and
default-type directives to preserve runtime DNS re-resolution for the backend
used by the rendered proxy_pass target. Add an appropriate resolver
configuration, or otherwise ensure the frontend reloads when BACKEND_HOST
changes, so recreated backend containers do not leave proxy requests targeting a
stale IP.
- Around line 35-40: Update the proxy_set_header Host directive in the
proxy_pass configuration to forward $proxy_host instead of $host, ensuring the
backend receives the configured BACKEND_HOST while leaving the other forwarded
headers unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 51db0c86-b2ee-4d3c-acb1-f91b6d4c53b8
📒 Files selected for processing (5)
DOCKER.mdREADME.mdREADME_zh.mddocker-compose.ymlnginx.conf.template
✅ Files skipped from review due to trivial changes (3)
- README.md
- README_zh.md
- DOCKER.md
🚧 Files skipped from review as they are similar to previous changes (1)
- docker-compose.yml
- nginx.conf.template: restore a configurable resolver (RESOLVER env, default 127.0.0.11) so the backend upstream is re-resolved at runtime (recreated backend containers no longer leave /api/ hitting a stale IP) — coderabbitai Major stability finding - nginx.conf.template: proxy_set_header Host $proxy_host (forwards the configured BACKEND_HOST) instead of $host — coderabbitai Minor - Dockerfile: export RESOLVER (default 127.0.0.11) and include it in the envsubst substitution so the resolver is overridable for Kubernetes/ECS (keeps the image portable, addressing the earlier gemini portability concern without a hardcoded Docker-only resolver)
Summary
Closes #239. Publish the project's frontend as a pre-built Docker image to GHCR, mirroring the existing backend image, so users can either
docker runthe image directly or usedocker-compose up -dwithout cloning/building locally.Changes
.github/workflows/docker-publish-frontend.yml— independent of the backend workflow; imagegithub-stars-manager-frontend; triggers on main/tag/workflow_dispatch; multi-arch amd64+arm64;latest/semver/sha-tags (identical scheme to backend).nginx.conf.template+ modifiedDockerfile— backend proxy upstream made configurable viaBACKEND_HOSTenv (defaultbackend:3000), rendered at startup withenvsubst..dockerignore— slims the frontend build context (excludes.git,server,node_modules, etc.).docker-compose.yml— frontend now pulls the published GHCR image (FRONTEND_IMAGE_TAG), keeps a commented localbuild: .option, setsBACKEND_HOST.DOCKER.md/README.md/README_zh.md— document the frontend image,FRONTEND_IMAGE_TAGandBACKEND_HOST.nginx.conf(superseded by the template).Protected (untouched)
docker-publish.yml(backend image),build-desktop.yml(desktop packaging),server/Dockerfile.Verification
docker buildsucceeds; container serves/(HTTP 200) and proxies/api/to the configured upstream for both default and externalBACKEND_HOST.Note
Do not merge to
main— the maintainer will test and merge manually.Summary by CodeRabbit
/apiviaBACKEND_HOST.FRONTEND_IMAGE_TAG, expanded image tag guidance, and clearer quick-start commands..dockerignoreto reduce Docker build context.