Networking Essentials
Cloudflare’s networking services connect your Workers and local services to the internet. This covers the developer-relevant parts: Tunnels for exposing services, Access for auth, DNS for domains, and Turnstile for bot protection.
Tunnels
Tunnels let you expose a local service (running on your machine or a private server) to the internet through Cloudflare’s network. No port forwarding, no public IP required.
How Tunnels Work
flowchart LR
A["Browser"] --> B["CF Edge\n(300+ locations)"]
B --> C["Tunnel\n(encrypted)"]
C --> D["cloudflared\n(your server)"]
D --> E["Local Service\n(localhost:8080)"]
The cloudflared daemon runs on your server and creates an outbound connection to Cloudflare’s edge. Traffic flows: browser -> CF edge -> tunnel -> cloudflared -> local service. Your origin never opens inbound ports.
Quick Setup
# Install cloudflared
brew install cloudflared # macOS
# or: sudo apt install cloudflared # Debian/Ubuntu
# Login (one time)
cloudflared tunnel login
# Create a named tunnel
cloudflared tunnel create my-tunnel
# Run it - expose localhost:8080 at my-tunnel.your-domain.com
cloudflared tunnel route dns my-tunnel my-tunnel.your-domain.com
cloudflared tunnel run --url http://localhost:8080 my-tunnel
Quick Tunnel (No Config)
For quick development, cloudflared tunnel --url creates a temporary public URL:
# Instant public URL for local dev server
cloudflared tunnel --url http://localhost:3000
# Prints: https://random-name.trycloudflare.com
This is useful for testing webhooks locally - point the webhook provider at the temporary URL.
Use Cases for Developers
- Webhook development: receive GitHub/Stripe/etc webhooks on your local machine
- Staging environments: expose a dev server to testers without deploying
- Private service access: connect a Worker to an internal API behind a firewall
- Self-hosted services: expose home servers (media, git, monitoring) securely
Access
Cloudflare Access adds SSO-based authentication in front of any web application. You define who can access a URL, and Cloudflare handles the login flow before traffic reaches your origin.
When to Use Access
- Protect staging/preview environments with SSO
- Add auth to internal tools without changing the app
- Gate access to admin dashboards
Basic Setup
- Go to Zero Trust > Access > Applications in the Cloudflare dashboard
- Add an application (self-hosted type)
- Set the application domain (e.g.,
staging.your-domain.com) - Create a policy: allow emails ending in
@your-company.com
Access supports identity providers (Google, GitHub, Okta, SAML) and one-time PIN via email. For most developer setups, GitHub or Google OAuth is sufficient.
Programmatic Access
Workers can verify Access JWTs to check identity:
// Verify the CF-Access-Jwt-Assertion header
const jwt = request.headers.get("Cf-Access-Jwt-Assertion");
if (!jwt) return new Response("Unauthorized", { status: 401 });
// Validate against your Access policy's public keys
// CF_ACCESS_AUD is your application's audience tag
const isValid = await verifyAccessJwt(jwt, env.CF_ACCESS_AUD);
DNS
Adding a Domain
- Add the domain in the Cloudflare dashboard
- Update your registrar’s nameservers to the ones Cloudflare provides
- Wait for propagation (usually minutes, sometimes up to 24h)
Proxied vs DNS-Only Records
| Record Setting | What Happens | Use For |
|---|---|---|
| Proxied (orange cloud) | Traffic flows through CF’s network; DDoS protection, caching, Workers active | Web traffic, APIs |
| DNS-only (gray cloud) | CF just resolves the DNS; traffic goes direct to origin | Mail servers, SSH, non-HTTP services |
Common Records
Type Name Content Proxy
A example.com 192.0.2.1 Proxied
AAAA example.com 2001:db8::1 Proxied
CNAME www example.com Proxied
CNAME tunnel <tunnel-id>.cfargotunnel.com Proxied
MX example.com mail.provider.com DNS only
TXT example.com "v=spf1 ..." DNS only
DNSSEC
Enable DNSSEC in the dashboard under DNS > Settings. Cloudflare provides a DS record - add it at your registrar. This prevents DNS spoofing.
Turnstile
Turnstile is Cloudflare’s CAPTCHA replacement. It verifies visitors are human without showing puzzles, using browser signals and machine learning.
Client-Side Integration
<!-- Add the Turnstile widget -->
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
<form action="/submit" method="POST">
<div class="cf-turnstile" data-sitekey="YOUR_SITE_KEY"></div>
<button type="submit">Submit</button>
</form>
The widget generates a cf-turnstile-response token that you verify server-side.
Server-Side Verification
app.post("/submit", async (c) => {
const formData = await c.req.formData();
const token = formData.get("cf-turnstile-response");
// Verify with Cloudflare
const result = await fetch(
"https://challenges.cloudflare.com/turnstile/v0/siteverify",
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
secret: c.env.TURNSTILE_SECRET,
response: token,
remoteip: c.req.header("CF-Connecting-IP"),
}),
}
);
const outcome = await result.json<{ success: boolean }>();
if (!outcome.success) {
return c.json({ error: "verification failed" }, 403);
}
// Process the form
return c.json({ submitted: true });
});
Modes
| Mode | Behavior | Use For |
|---|---|---|
| Managed | Cloudflare decides if challenge is needed | Most forms |
| Non-interactive | Never shows a challenge, still verifies | API endpoints, invisible protection |
| Invisible | Like non-interactive but with fallback challenges | High-security forms |
Turnstile is free for unlimited use. Set it up in the Cloudflare dashboard under Turnstile, create a site, and get the site key and secret key.