Add Cloudflare Tunnel support for development - #119
Conversation
- Add tunnel.cambeerfestival.app to worker CORS allowed origins - Add *.trycloudflare.com wildcard support for quick tunnels - Create dev and dev-tunnel tasks in mise.dev.toml - Add tunnel-setup task for one-time tunnel configuration - Add .cloudflared/config.yml for tunnel configuration - Update .gitignore to exclude tunnel credentials 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
LCOV of commit
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
🚀 Cloudflare Pages PreviewYour preview deployment is ready! Preview URL: https://richardthe3rd-cloudflare-tun.staging-cambeerfestival.pages.dev This preview will be automatically updated when you push new commits to this PR. |
There was a problem hiding this comment.
Pull request overview
This PR adds Cloudflare Tunnel support to enable secure public HTTPS access to local development servers. The implementation provides automated setup tasks via mise and adds CORS configuration to support the tunnel domain. However, the PR introduces security concerns and portability issues that should be addressed before merging.
Key changes:
- Adds Cloudflare Tunnel configuration with automated mise tasks for setup and running
- Updates CORS configuration to allow the tunnel domain and quick tunnels
- Moves the
devtask from global to developer-specific configuration
Reviewed changes
Copilot reviewed 4 out of 5 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
.cloudflared/config.yml |
New tunnel configuration with hardcoded developer-specific credentials path |
.gitignore |
Excludes tunnel credentials and certificates from version control |
cloudflare-worker/worker.js |
Adds tunnel domain and wildcard quick tunnel CORS allowance to production worker |
mise.toml |
Removes dev task (moved to mise.dev.toml) |
mise.dev.toml |
Adds cloudflared tool, tunnel setup task, and combined dev-tunnel task |
|
|
||
| tunnel: cbf-dev-tunnel | ||
| credentials-file: /home/vscode/.cloudflared/be8d5634-735e-4637-b030-6f818e739b77.json |
There was a problem hiding this comment.
The hardcoded UUID in the credentials file path (be8d5634-735e-4637-b030-6f818e739b77.json) appears to be developer-specific and will differ for each developer who runs cloudflared tunnel create. This will cause the tunnel to fail for other developers.
The tunnel-setup task creates a tunnel, which generates a unique UUID for each tunnel instance. Since this UUID is different for every developer, the config file should either:
- Use a dynamic path that cloudflared can resolve automatically, or
- Include instructions in the config file comments for developers to update this value after running
tunnel-setup, or - Have the
tunnel-setuptask automatically update the config file with the correct UUID
Option 3 would provide the best developer experience.
| tunnel: cbf-dev-tunnel | |
| credentials-file: /home/vscode/.cloudflared/be8d5634-735e-4637-b030-6f818e739b77.json | |
| # The credentials file is auto-resolved by cloudflared; do not hardcode the path. | |
| tunnel: cbf-dev-tunnel |
| # 1. Login to Cloudflare: cloudflared tunnel login | ||
| # 2. Create the tunnel: cloudflared tunnel create cbf-dev-tunnel | ||
| # 3. Route DNS: cloudflared tunnel route dns cbf-dev-tunnel tunnel.cambeerfestival.app | ||
| # 4. Run the tunnel: cloudflared tunnel run cbf-dev-tunnel | ||
| # |
There was a problem hiding this comment.
[nitpick] The setup instructions in the comments reference manual cloudflared commands, but developers are expected to use the tunnel-setup mise task instead. The comments should be updated to reference the mise task for consistency:
# Setup instructions:
# Run the automated setup: MISE_ENV=dev ./bin/mise run tunnel-setup
#
# Or set up manually:
# 1. Login to Cloudflare: cloudflared tunnel login
# 2. Create the tunnel: cloudflared tunnel create cbf-dev-tunnel
# 3. Route DNS: cloudflared tunnel route dns cbf-dev-tunnel tunnel.cambeerfestival.app
# 4. Update credentials-file path below with your tunnel UUID
# 5. Run the tunnel: MISE_ENV=dev ./bin/mise run dev-tunnel| # 1. Login to Cloudflare: cloudflared tunnel login | |
| # 2. Create the tunnel: cloudflared tunnel create cbf-dev-tunnel | |
| # 3. Route DNS: cloudflared tunnel route dns cbf-dev-tunnel tunnel.cambeerfestival.app | |
| # 4. Run the tunnel: cloudflared tunnel run cbf-dev-tunnel | |
| # | |
| # Recommended: Run the automated setup task: | |
| # MISE_ENV=dev ./bin/mise run tunnel-setup | |
| # | |
| # Or set up manually (if needed): | |
| # 1. Login to Cloudflare: cloudflared tunnel login | |
| # 2. Create the tunnel: cloudflared tunnel create cbf-dev-tunnel | |
| # 3. Route DNS: cloudflared tunnel route dns cbf-dev-tunnel tunnel.cambeerfestival.app | |
| # 4. Update the credentials-file path below with your tunnel UUID | |
| # 5. Run the tunnel: MISE_ENV=dev ./bin/mise run dev-tunnel | |
| # |
| echo "" | ||
| echo "Step 3: Setting up DNS route for tunnel.cambeerfestival.app..." | ||
| cloudflared tunnel route dns cbf-dev-tunnel tunnel.cambeerfestival.app |
There was a problem hiding this comment.
The DNS routing step runs unconditionally on every tunnel-setup execution, which could cause issues or confusion if the route already exists. Consider adding a check similar to the tunnel existence check:
# Check if DNS route already exists
if cloudflared tunnel route list 2>/dev/null | grep -q "tunnel.cambeerfestival.app"; then
echo "✓ DNS route for tunnel.cambeerfestival.app already exists"
else
echo ""
echo "Step 3: Setting up DNS route for tunnel.cambeerfestival.app..."
cloudflared tunnel route dns cbf-dev-tunnel tunnel.cambeerfestival.app
fiThis prevents duplicate route creation attempts and provides clearer feedback to developers.
| echo "" | |
| echo "Step 3: Setting up DNS route for tunnel.cambeerfestival.app..." | |
| cloudflared tunnel route dns cbf-dev-tunnel tunnel.cambeerfestival.app | |
| # Check if DNS route already exists | |
| if cloudflared tunnel route list 2>/dev/null | grep -q "tunnel.cambeerfestival.app"; then | |
| echo "✓ DNS route for tunnel.cambeerfestival.app already exists" | |
| else | |
| echo "" | |
| echo "Step 3: Setting up DNS route for tunnel.cambeerfestival.app..." | |
| cloudflared tunnel route dns cbf-dev-tunnel tunnel.cambeerfestival.app | |
| fi |
| # Wait for tunnel to be ready | ||
| echo "Waiting for tunnel to start..." | ||
| sleep 3 | ||
|
|
||
| echo "" | ||
| echo "✅ Tunnel running at: https://tunnel.cambeerfestival.app" | ||
| echo "" | ||
| echo "Starting Flutter dev server on http://localhost:8080" | ||
| echo "Press Ctrl+C to stop both services." | ||
| echo "" | ||
|
|
||
| # Cleanup function | ||
| cleanup() { | ||
| echo "" | ||
| echo "Stopping tunnel..." | ||
| kill $TUNNEL_PID 2>/dev/null |
There was a problem hiding this comment.
The dev-tunnel task uses kill $TUNNEL_PID 2>/dev/null which may not properly clean up the cloudflared process if it has spawned child processes. Consider using kill -- -$TUNNEL_PID to kill the entire process group, or use a more robust cleanup mechanism.
Additionally, the 3-second sleep is arbitrary and may not be sufficient for the tunnel to fully start, especially on slower systems. Consider adding a retry loop that checks if the tunnel is actually responding:
# Wait for tunnel to be ready
echo "Waiting for tunnel to start..."
max_attempts=10
attempt=0
while ! curl -s -o /dev/null -w "%{http_code}" https://tunnel.cambeerfestival.app/health | grep -q "200"; do
attempt=$((attempt + 1))
if [ $attempt -ge $max_attempts ]; then
echo "Tunnel failed to start after ${max_attempts} seconds"
kill $TUNNEL_PID 2>/dev/null
exit 1
fi
sleep 1
done| // Allow Cloudflare Tunnel quick tunnels (*.trycloudflare.com) | ||
| // Used for local development with cloudflared tunnel | ||
| // Security note: These are temporary development tunnels controlled by Cloudflare. | ||
| // Only enable this in development/staging workers, not production. | ||
| if (origin.endsWith('.trycloudflare.com')) { | ||
| return { | ||
| 'Access-Control-Allow-Origin': origin, | ||
| 'Access-Control-Allow-Credentials': 'true', | ||
| }; | ||
| } | ||
|
|
There was a problem hiding this comment.
The wildcard CORS allowance for *.trycloudflare.com is being added to the worker without any environment checks. According to the security note in the comment, this should "only enable this in development/staging workers, not production."
However, looking at cloudflare-worker/wrangler.toml, there's only one worker environment configured (ENVIRONMENT = "production"), and this worker is deployed directly to production via the GitHub workflow when changes are merged to main.
This creates a security risk where the production worker will allow CORS from any *.trycloudflare.com origin, which could potentially be exploited.
Recommended solutions:
- Remove this wildcard allowance if there's no separate dev/staging worker deployment, or
- Set up separate worker environments (dev/staging/production) with different CORS configurations, or
- Add runtime environment checks in the worker code to only enable this for non-production environments
| // Allow Cloudflare Tunnel quick tunnels (*.trycloudflare.com) | |
| // Used for local development with cloudflared tunnel | |
| // Security note: These are temporary development tunnels controlled by Cloudflare. | |
| // Only enable this in development/staging workers, not production. | |
| if (origin.endsWith('.trycloudflare.com')) { | |
| return { | |
| 'Access-Control-Allow-Origin': origin, | |
| 'Access-Control-Allow-Credentials': 'true', | |
| }; | |
| } |
Summary
Adds Cloudflare Tunnel support to enable secure public HTTPS access to local development servers at
tunnel.cambeerfestival.app. This improves the development workflow by providing:Changes
Infrastructure
.cloudflared/config.yml- Cloudflare Tunnel configuration for cbf-dev-tunnel routing to localhost:8080.gitignore- Added exclusions for tunnel credentials and certificatesCORS Configuration
cloudflare-worker/worker.js- Addedtunnel.cambeerfestival.appto allowed origins and support for quick tunnels (*.trycloudflare.com)Development Tools
mise.dev.toml- Added cloudflared tool and new mise tasks:tunnel-setup- One-time tunnel configuration (login, create, route DNS)dev-tunnel- Runs both tunnel and Flutter dev server togetherdevtask here from mise.toml (developer-only)mise.toml- Removeddevtask (now in mise.dev.toml)Usage
First-time setup:
Daily development:
This will start both the Cloudflare Tunnel and Flutter dev server, accessible at:
Test plan
🤖 Generated with Claude Code