How to Share Your Local WordPress or Drupal Site with Cloudflare Tunnel (Free)
When developing locally with DDEV, you might need to share your work with clients, test webhooks from external services, or collaborate with remote team members. Cloudflare Tunnel provides a secure, simple way to expose your local development sites to the internet without opening firewall ports or dealing with complex networking configurations.
What is Cloudflare Tunnel?
Cloudflare Tunnel (formerly Argo Tunnel) is part of Cloudflare's Zero Trust networking solution. It creates a secure, outbound-only connection from your local machine to Cloudflare's edge network, which then routes public traffic to your local services. This means:
- No open inbound ports - Your firewall stays secure
- No public IP required - Works behind NAT and corporate firewalls
- Free for development use - Cloudflare's quick tunnels are free
- HTTPS by default - Automatic SSL/TLS encryption
- Simple setup - Just one command to get started
What is DDEV?
DDEV is a Docker-based local development environment that makes it easy to set up PHP projects (Drupal, WordPress, Laravel, etc.) with minimal configuration. It provides:
- Pre-configured containers for web, database, and other services
- Support for multiple PHP versions
- Built-in SSL certificates for local HTTPS
- Command-line tools for common development tasks
Using DDEV with Cloudflare Tunnel lets you run your site locally and share it publicly whenever needed.
Prerequisites
Before we begin, make sure you have:
- A Mac, Linux, or Windows machine with Docker installed
- DDEV installed and configured (official installation guide or check out my guide on setting up DDEV for WordPress and Drupal)
- A working DDEV project (we'll use example sites like
myproject.ddev.site
andclient-site.ddev.site
) - Basic command-line familiarity
- No Cloudflare account required for quick tunnels (the method covered in this guide)
Note: If you want persistent URLs with custom domains (covered later), you'll need a free Cloudflare account.
Step 1: Install Cloudflared
The cloudflared
daemon is the client that creates the tunnel connection. Installation varies by platform:
macOS (Homebrew)
brew install cloudflared
Linux (Debian/Ubuntu)
wget -q https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared-linux-amd64.deb
Linux (RHEL/CentOS)
wget -q https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-x86_64.rpm
sudo rpm -i cloudflared-linux-x86_64.rpm
Windows
Download the installer from the Cloudflare downloads page or use Chocolatey:
choco install cloudflared
Verify the installation:
cloudflared --version
Step 2: Start Your DDEV Site
Make sure your DDEV project is running. Navigate to your project directory and start DDEV:
cd /path/to/your/project
ddev start
Your site will be available locally at something like https://yourproject.ddev.site
. Verify it works by opening it in your browser.
Step 3: Create a Cloudflare Tunnel to Your DDEV Site
Here's where it gets interesting. Run one command and cloudflared creates a tunnel with a public URL automatically. No account setup, no authentication, no configuration needed. The basic syntax is:
cloudflared tunnel --url <local-url> --http-host-header <hostname>
Example 1: My Project Site
cloudflared tunnel --url https://myproject.ddev.site/ --http-host-header myproject.ddev.site
Example 2: Client Site
cloudflared tunnel --url https://client-site.ddev.site/ --http-host-header client-site.ddev.site
After running this command, you'll see output like:
2025-10-14T10:30:15Z INF Thank you for trying Cloudflare Tunnel. Doing so, without a Cloudflare account, is a quick way to experiment and try it out. However, be aware that these account-less Tunnels have no uptime guarantee. If you intend to use Tunnels in production you should use a pre-created named tunnel by following: https://developers.cloudflare.com/cloudflare-one/connections/connect-apps
2025-10-14T10:30:15Z INF Requesting new quick Tunnel on trycloudflare.com...
2025-10-14T10:30:16Z INF +--------------------------------------------------------------------------------------------+
2025-10-14T10:30:16Z INF | Your quick Tunnel has been created! Visit it at (it may take some time to be reachable): |
2025-10-14T10:30:16Z INF | https://randomly-generated-subdomain.trycloudflare.com |
2025-10-14T10:30:16Z INF +--------------------------------------------------------------------------------------------+
Copy the generated URL (e.g., https://randomly-generated-subdomain.trycloudflare.com
) and share it with anyone who needs access to your local site!
Understanding the Command Parameters
Let's break down what each parameter does:
--url
: The local URL where your DDEV site is running. Use HTTPS if your DDEV site uses SSL (which it does by default).--http-host-header
: This is crucial for DDEV. It tells cloudflared to forward the correct hostname in the HTTP Host header. DDEV routes requests based on this header, so without it, you'll get a "404 Not Found" or see the wrong site.
Why is --http-host-header Necessary?
DDEV's router uses virtual hosting, meaning multiple sites can run on the same IP address and port. The router determines which site to serve based on the Host
header in the HTTP request.
When traffic comes through Cloudflare Tunnel, the Host header would normally be the Cloudflare-generated domain (like randomly-generated-subdomain.trycloudflare.com
). By specifying --http-host-header myproject.ddev.site
, we override this and ensure DDEV sees the correct hostname.
Using Named Tunnels for Persistent URLs
The quick tunnel method above is perfect for ad-hoc sharing, but the URL changes each time you run the command and there's no uptime guarantee. If you need a persistent URL with your own custom domain (like myproject.example.com
), you can create a named tunnel. This requires a free Cloudflare account.
1. Authenticate with Cloudflare
cloudflared tunnel login
This opens a browser to authenticate with your Cloudflare account.
2. Create a Named Tunnel
cloudflared tunnel create my-ddev-tunnel
This generates a tunnel ID and credentials file.
3. Create a Configuration File
Create ~/.cloudflared/config.yml
:
tunnel: <TUNNEL-ID>
credentials-file: /Users/yourusername/.cloudflared/<TUNNEL-ID>.json
ingress:
- hostname: mysite.example.com
service: https://myproject.ddev.site
originRequest:
httpHostHeader: myproject.ddev.site
noTLSVerify: true
- service: http_status:404
Note: noTLSVerify: true
is needed because DDEV uses self-signed certificates.
4. Route Your Domain
cloudflared tunnel route dns my-ddev-tunnel mysite.example.com
5. Run the Tunnel
cloudflared tunnel run my-ddev-tunnel
Your site is now accessible at https://mysite.example.com
with a persistent URL!
Common Use Cases
1. Client Demos
Share work-in-progress sites with clients without deploying to staging servers:
cloudflared tunnel --url https://client-demo.ddev.site/ --http-host-header client-demo.ddev.site
Send the generated URL to your client for instant feedback.
2. Webhook Testing
Test webhooks from services like Stripe, GitHub, or Twilio that require a public URL:
cloudflared tunnel --url https://webhooks.ddev.site/ --http-host-header webhooks.ddev.site
Configure the webhook in the external service to point to your Cloudflare URL.
3. Mobile Device Testing
Test your responsive designs on real mobile devices without being on the same network:
cloudflared tunnel --url https://mobile-test.ddev.site/ --http-host-header mobile-test.ddev.site
Open the Cloudflare URL on your phone to test on real devices.
4. Remote Collaboration
Share your development environment with remote teammates:
cloudflared tunnel --url https://team-collab.ddev.site/ --http-host-header team-collab.ddev.site
Your team can access the site as if they were running it locally.
Troubleshooting
Getting a 404 or Wrong Site
Make sure you're using the --http-host-header
parameter with the correct DDEV hostname:
cloudflared tunnel --url https://mysite.ddev.site/ --http-host-header mysite.ddev.site
SSL Certificate Errors
If you're using a named tunnel with a config file, add noTLSVerify: true
to the origin request section since DDEV uses self-signed certificates.
Tunnel Not Starting
Check if cloudflared is already running:
ps aux | grep cloudflared
Kill any existing processes if needed:
pkill cloudflared
DDEV Site Not Accessible Locally
Verify your DDEV site is running:
ddev describe
Make sure the URL you're using matches the output.
Security Considerations
While Cloudflare Tunnel is secure by design, keep these points in mind:
- Don't expose production databases - Only tunnel development sites with non-sensitive data
- Quick tunnels are temporary - URLs expire and shouldn't be relied upon for production
- Use authentication - For sensitive projects, add Cloudflare Access authentication to your named tunnels
- Monitor tunnel access - Check Cloudflare Analytics to see who's accessing your tunnels
- Shut down tunnels when done - Use Ctrl+C to stop the tunnel when you're finished
Alternative: DDEV's Built-in Share Command
DDEV also has a built-in ddev share
command that uses ngrok. However, Cloudflare Tunnel offers several advantages:
- Free without rate limits (ngrok free tier has limits)
- Better performance through Cloudflare's global network
- Integration with Cloudflare Zero Trust for advanced features
- Persistent named tunnels with custom domains
That said, ddev share
is even simpler if you just need something quick and don't want to install additional tools.
Simplifying the Process with ddev-share-cf
To make this process even easier, I've created the ddev-share-cf DDEV addon. This addon integrates Cloudflare Tunnel directly into DDEV, allowing you to share your local sites with a simple command without manually managing cloudflared or configuration files.
Installation
Install the addon with a single command:
ddev get davo20019/ddev-share-cf
Usage
Once installed, simply run:
ddev share-cf
The addon handles all the tunnel configuration automatically, making it as easy as DDEV's built-in share command but with all the benefits of Cloudflare Tunnel.