-
Notifications
You must be signed in to change notification settings - Fork 3.1k
refactor: migrate from nginx to Caddy for admin and web services #8338
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: preview
Are you sure you want to change the base?
refactor: migrate from nginx to Caddy for admin and web services #8338
Conversation
- Updated Dockerfiles to use Caddy as the web server instead of nginx. - Added Caddyfile configurations for both admin and web services. - Implemented rate limiting in Caddy using xcaddy. - Adjusted healthcheck endpoint to reflect new routing in Caddy.
WalkthroughReplaces Nginx with Caddy for both admin and web apps: Dockerfiles now build a custom Caddy (xcaddy + ratelimit) and use Caddy in production; nginx.conf files were removed and new Caddyfile configs serve SPA static files on port 3000. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (3)
💤 Files with no reviewable changes (2)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (1)
apps/admin/Dockerfile.admin (1)
76-98: Caddy multi‑stage looks good; double‑checkcurlavailability for HEALTHCHECKThe Caddy build + production stages and static file layout look sound, and copying
/usr/bin/caddyfromcaddy-buildercorrectly brings in the ratelimit‑enabled binary.One thing to verify:
HEALTHCHECKusescurl, but thecaddy:2.11-alpinebase typically doesn’t ship withcurlby default. If you rely on Docker’s health status, consider either:
- Installing curl in the production stage (e.g.,
RUN apk add --no-cache curl), or- Switching the healthcheck to a tool that’s already present in the image.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
apps/admin/Dockerfile.admin(1 hunks)apps/admin/caddy/Caddyfile(1 hunks)apps/web/Dockerfile.web(1 hunks)apps/web/caddy/Caddyfile(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Build packages
- GitHub Check: Analyze (javascript)
| { | ||
| servers { | ||
| trusted_proxies static 0.0.0.0 | ||
| } | ||
| } | ||
|
|
||
| :3000 { | ||
| root * /usr/share/caddy/html | ||
| try_files {path} /index.html | ||
| file_server | ||
|
|
||
| # Access logs to stdout (default in Caddy) | ||
| log { | ||
| output stdout | ||
| format console | ||
| } | ||
| } No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# Find relevant Dockerfile and Caddyfile configurations
find . -type f -name "Dockerfile*" | grep -E "(admin|web)" | head -20Repository: makeplane/plane
Length of output: 174
🏁 Script executed:
# Check the admin build copy destination
find . -path "*/admin/*" -name "Dockerfile*" -exec cat {} \;Repository: makeplane/plane
Length of output: 174
🏁 Script executed:
# Look at the web Caddyfile for comparison
find . -type f -name "Caddyfile" | head -10Repository: makeplane/plane
Length of output: 114
🏁 Script executed:
cat -n ./apps/admin/caddy/CaddyfileRepository: makeplane/plane
Length of output: 400
🏁 Script executed:
cat -n ./apps/web/caddy/CaddyfileRepository: makeplane/plane
Length of output: 400
🏁 Script executed:
# Find admin Dockerfile and examine the COPY instructions
find ./apps/admin -name "Dockerfile*" -exec cat -n {} +Repository: makeplane/plane
Length of output: 4143
Admin SPA fallback for /god-mode is broken — requests to nested routes will fail
With root * /usr/share/caddy/html and the admin build copied to /usr/share/caddy/html/god-mode, requests like /god-mode/projects/123 will attempt to fall back to /usr/share/caddy/html/index.html instead of /usr/share/caddy/html/god-mode/index.html. Since the latter directory exists but the former does not in this container, deep-linked admin routes will fail. Fix this by updating the fallback path:
- try_files {path} /index.html
+ try_files {path} /god-mode/index.htmlAdditional issues:
trusted_proxies static 0.0.0.0effectively trusts all IPv4 client addresses. Constrain this to your actual proxy/load-balancer IP ranges or remove it if not needed.- The ratelimit plugin is compiled into Caddy (via xcaddy) but no
rate_limitdirective is configured in the Caddyfile, leaving it unused.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| { | |
| servers { | |
| trusted_proxies static 0.0.0.0 | |
| } | |
| } | |
| :3000 { | |
| root * /usr/share/caddy/html | |
| try_files {path} /index.html | |
| file_server | |
| # Access logs to stdout (default in Caddy) | |
| log { | |
| output stdout | |
| format console | |
| } | |
| } | |
| { | |
| servers { | |
| trusted_proxies static 0.0.0.0 | |
| } | |
| } | |
| :3000 { | |
| root * /usr/share/caddy/html | |
| try_files {path} /god-mode/index.html | |
| file_server | |
| # Access logs to stdout (default in Caddy) | |
| log { | |
| output stdout | |
| format console | |
| } | |
| } |
🤖 Prompt for AI Agents
In apps/admin/caddy/Caddyfile around lines 1 to 17, the SPA fallback currently
always serves /usr/share/caddy/html/index.html which breaks deep links under
/god-mode (e.g. /god-mode/projects/123) because the admin build lives in
/usr/share/caddy/html/god-mode; update the fallback so requests under the
/god-mode path return /usr/share/caddy/html/god-mode/index.html (use a
conditional or a separate site block/route that sets try_files {path}
/god-mode/index.html for paths starting with /god-mode). Also tighten or remove
the overly broad trusted_proxies static 0.0.0.0 entry to only include your
proxy/load-balancer CIDRs (or delete it if not needed) and either configure the
rate_limit directive where required or remove the unused rate-limit plugin from
the build to avoid confusion.
| { | ||
| servers { | ||
| trusted_proxies static 0.0.0.0 | ||
| } | ||
| } | ||
|
|
||
| :3000 { | ||
| root * /usr/share/caddy/html | ||
| try_files {path} /index.html | ||
| file_server | ||
|
|
||
| # Access logs to stdout (default in Caddy) | ||
| log { | ||
| output stdout | ||
| format console | ||
| } | ||
| } No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# First, check if the Caddyfile exists and view its content
find . -name "Caddyfile" -type fRepository: makeplane/plane
Length of output: 114
🏁 Script executed:
# Search for Docker build configurations that might contain xcaddy with ratelimit
find . -name "Dockerfile*" -type f | head -20Repository: makeplane/plane
Length of output: 399
🏁 Script executed:
# Look for any rate_limit directives in the codebase
rg "rate_limit" --type-listRepository: makeplane/plane
Length of output: 448
🏁 Script executed:
# Correct search for rate_limit directives
rg "rate_limit" --type caddyRepository: makeplane/plane
Length of output: 88
🏁 Script executed:
# View the Caddyfile being reviewed
cat -n ./apps/web/caddy/CaddyfileRepository: makeplane/plane
Length of output: 400
🏁 Script executed:
# Check the Docker build config for the web app
cat -n ./apps/web/Dockerfile.web | head -50Repository: makeplane/plane
Length of output: 2194
🏁 Script executed:
# Look for xcaddy or ratelimit references in Docker files
rg "xcaddy|ratelimit|caddy-ratelimit" DockerfileRepository: makeplane/plane
Length of output: 109
🏁 Script executed:
# Search for xcaddy or ratelimit in all Dockerfiles
rg "xcaddy|ratelimit|caddy-ratelimit" ./apps/web/Repository: makeplane/plane
Length of output: 177
🏁 Script executed:
# Check the full web Dockerfile.web
cat -n ./apps/web/Dockerfile.web | tail -50Repository: makeplane/plane
Length of output: 1817
🏁 Script executed:
# Search the admin Caddyfile for comparison
cat -n ./apps/admin/caddy/CaddyfileRepository: makeplane/plane
Length of output: 400
🏁 Script executed:
# Search for any rate_limit in all files
rg "rate_limit"Repository: makeplane/plane
Length of output: 998
🏁 Script executed:
# Check Caddy documentation or configuration context - look for comments or related config
rg "trusted_proxies|X-Forwarded" --context 3Repository: makeplane/plane
Length of output: 1770
🏁 Script executed:
# Check if there's any rate_limit usage or configuration elsewhere in the web app
rg "rate_limit" ./apps/web/Repository: makeplane/plane
Length of output: 41
🏁 Script executed:
# Check if the PR or any related docs mention rate limiting intent
find . -name "*.md" -type f | xargs rg -l "rate" 2>/dev/null | head -10Repository: makeplane/plane
Length of output: 432
🏁 Script executed:
# Check for any rate_limit directives in Caddyfiles
rg "rate_limit" ./apps/*/caddy/Repository: makeplane/plane
Length of output: 41
🏁 Script executed:
# Check git history or comments around the xcaddy ratelimit addition
git log --oneline --all -- "**/Dockerfile.web" | head -20Repository: makeplane/plane
Length of output: 1365
🏁 Script executed:
# Look at proxy Caddyfile to understand the architecture better
cat -n ./apps/proxy/Caddyfile.ceRepository: makeplane/plane
Length of output: 1099
Revisit trusted_proxies scope and consider wiring the ratelimit module
trusted_proxies static 0.0.0.0treats all clients as trusted proxies, allowing any source to supplyX-Forwarded-For/ related headers that Caddy will trust. While the web app is behind the proxy layer, this setting is unnecessarily permissive; restrict it to your actual proxy ranges (e.g.,trusted_proxies static 127.0.0.1).- The Docker image builds Caddy with
github.com/mholt/caddy-ratelimit, but norate_limitdirectives are configured in this Caddyfile. Either add rate limiting if needed or remove the unused module from the build to reduce image size.
🤖 Prompt for AI Agents
In apps/web/caddy/Caddyfile around lines 1–17, the trusted_proxies setting is
overly permissive (static 0.0.0.0) and the caddy-ratelimit module is built but
not used; restrict trusted_proxies to only your actual proxy ranges (for example
127.0.0.1 and any internal Docker/CNI subnet or load‑balancer CIDRs) so Caddy
only trusts X-Forwarded-* from those sources, and either add appropriate
rate_limit directives (site or global scope) to throttle abusive requests using
the built-in ratelimit syntax or remove the github.com/mholt/caddy-ratelimit
build tag from the Docker build to avoid shipping an unused module — update the
Caddyfile to reflect restricted CIDRs and, if adding rate limiting, configure
sensible limits and scopes for your app endpoints.
| # ***************************************************************************** | ||
| # STAGE 3: Serve with nginx | ||
| # STAGE 3: Serve with Caddy | ||
| # ***************************************************************************** | ||
| FROM nginx:1.27-alpine AS production | ||
|
|
||
| COPY apps/web/nginx/nginx.conf /etc/nginx/nginx.conf | ||
| COPY --from=installer /app/apps/web/build/client /usr/share/nginx/html | ||
| FROM caddy:2.11-builder-alpine AS caddy-builder | ||
|
|
||
| EXPOSE 3000 | ||
| RUN xcaddy build \ | ||
| --with github.com/mholt/caddy-ratelimit | ||
|
|
||
| FROM caddy:2.11-alpine AS production | ||
|
|
||
| COPY --from=builder /usr/bin/caddy /usr/bin/caddy | ||
|
|
||
| COPY apps/web/caddy/Caddyfile /etc/caddy/Caddyfile | ||
|
|
||
| HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ | ||
| CMD curl -fsS http://127.0.0.1:3000/ >/dev/null || exit 1 | ||
|
|
||
| CMD ["nginx", "-g", "daemon off;"] | ||
| COPY --from=installer /app/apps/web/build/client /usr/share/caddy/html | ||
|
|
||
| CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# First, let's locate and read the full Dockerfile.web to understand all stages
find . -name "Dockerfile.web" -type fRepository: makeplane/plane
Length of output: 84
🏁 Script executed:
# Also find the admin Dockerfile mentioned in the comment
find . -name "Dockerfile.admin" -o -name "Dockerfile" | grep -i admin | head -5Repository: makeplane/plane
Length of output: 88
🏁 Script executed:
# Read the full Dockerfile.web
cat -n ./apps/web/Dockerfile.webRepository: makeplane/plane
Length of output: 3779
🏁 Script executed:
# Read the admin Dockerfile for comparison
cat -n ./apps/admin/Dockerfile.adminRepository: makeplane/plane
Length of output: 3708
🏁 Script executed:
# Check the difference between the two Dockerfiles for the Caddy stage
diff -u <(sed -n '79,95p' ./apps/web/Dockerfile.web) <(sed -n '80,98p' ./apps/admin/Dockerfile.admin)Repository: makeplane/plane
Length of output: 146
🏁 Script executed:
# Verify curl availability in caddy images by checking Docker documentation or image details
web_search "caddy:2.11-alpine curl available tools"Repository: makeplane/plane
Length of output: 109
🏁 Script executed:
# Check if there's any Docker-related documentation or comments in the repo
find . -type f \( -name "*.md" -o -name "*.txt" \) -exec grep -l "caddy\|curl" {} \; | head -10Repository: makeplane/plane
Length of output: 96
🌐 Web query:
caddy:2.11-alpine image what tools included curl
💡 Result:
Short answer: No — the official caddy:2.11-alpine image is a minimal Alpine-based image and does not include curl by default. You can add it with: apk add --no-cache curl. [1][2][3]
Sources:
- Official caddy Docker repo (alpine images are minimal). [1]
- Notes that default/small Caddy images omit utilities like curl; alpine variant only adds basic shell/utilities. [2]
- Alpine documentation/examples: curl is not installed by default; install via apk. [3]
🏁 Script executed:
# Also check the Caddyfile to understand what endpoints are expected
cat -n ./apps/web/caddy/CaddyfileRepository: makeplane/plane
Length of output: 400
Fix Caddy binary copy source and address curl/EXPOSE issues
COPY --from=builder /usr/bin/caddy /usr/bin/caddyon line 86 is incorrect: thebuilderstage is the Node build image (node:22-alpine) and does not contain a caddy binary. The compiled binary with the ratelimit plugin is in thecaddy-builderstage. The Docker build will fail or silently omit the ratelimit plugin. Change to:
-COPY --from=builder /usr/bin/caddy /usr/bin/caddy
+COPY --from=caddy-builder /usr/bin/caddy /usr/bin/caddy-
The HEALTHCHECK on lines 90–91 uses
curl, which is not present in thecaddy:2.11-alpinebase image. Either install curl viaRUN apk add --no-cache curlor use an alternative healthcheck command (e.g.,caddy list-modulesor a different probe). -
Add
EXPOSE 3000before the finalCMDto match the admin Dockerfile and document the exposed port. -
Lines 79 and 81 have unnecessary 2-space indentation; align them to column 0 for consistency with standard Dockerfile style.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| # ***************************************************************************** | |
| # STAGE 3: Serve with nginx | |
| # STAGE 3: Serve with Caddy | |
| # ***************************************************************************** | |
| FROM nginx:1.27-alpine AS production | |
| COPY apps/web/nginx/nginx.conf /etc/nginx/nginx.conf | |
| COPY --from=installer /app/apps/web/build/client /usr/share/nginx/html | |
| FROM caddy:2.11-builder-alpine AS caddy-builder | |
| EXPOSE 3000 | |
| RUN xcaddy build \ | |
| --with github.com/mholt/caddy-ratelimit | |
| FROM caddy:2.11-alpine AS production | |
| COPY --from=builder /usr/bin/caddy /usr/bin/caddy | |
| COPY apps/web/caddy/Caddyfile /etc/caddy/Caddyfile | |
| HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ | |
| CMD curl -fsS http://127.0.0.1:3000/ >/dev/null || exit 1 | |
| CMD ["nginx", "-g", "daemon off;"] | |
| COPY --from=installer /app/apps/web/build/client /usr/share/caddy/html | |
| CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile"] | |
| # ***************************************************************************** | |
| # STAGE 3: Serve with Caddy | |
| # ***************************************************************************** | |
| FROM caddy:2.11-builder-alpine AS caddy-builder | |
| RUN xcaddy build \ | |
| --with github.com/mholt/caddy-ratelimit | |
| FROM caddy:2.11-alpine AS production | |
| COPY --from=caddy-builder /usr/bin/caddy /usr/bin/caddy | |
| COPY apps/web/caddy/Caddyfile /etc/caddy/Caddyfile | |
| HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ | |
| CMD curl -fsS http://127.0.0.1:3000/ >/dev/null || exit 1 | |
| COPY --from=installer /app/apps/web/build/client /usr/share/caddy/html | |
| CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile"] |
🤖 Prompt for AI Agents
In apps/web/Dockerfile.web around lines 75 to 95, the Dockerfile incorrectly
copies the Caddy binary from the wrong stage and has portability/style issues:
change the COPY source to use the caddy-builder stage (COPY --from=caddy-builder
/usr/bin/caddy /usr/bin/caddy), fix the two lines with extra two-space
indentation so they start at column 0, address the HEALTHCHECK using curl which
is not present in the caddy:2.11-alpine image by either installing curl (e.g.,
add a RUN apk add --no-cache curl in the production stage) or replace the check
with a curl-free probe such as running a Caddy CLI check (e.g., caddy
list-modules) or a simple socket probe, and add EXPOSE 3000 before the final CMD
to document and expose the port.
prateekshourya29
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pratapalakshmi, we can also delete the nginx.conf file for all apps. We also have it for space app but it's not being used as well.
- Deleted nginx.conf files as part of the migration to Caddy. - Updated Dockerfile to reflect changes in the Caddy build process.
Description
Type of Change
Screenshots and Media (if applicable)
Test Scenarios
References
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.