Cloudflare Tunnel and Access Setup
This page defines the one-time Cloudflare setup for Anuva Development-stage Web and documentation previews. It covers the two Windows development machines, their remotely managed tunnels, published application routes, Cloudflare Access policy, local connector credentials, and verification.
It does not configure Early Users or Production infrastructure. The canonical documentation publisher remains a separate manual workflow.
Phase 6 machine replication verifies the existing machine-two tunnel, token file boundary, twelve published routes, certificates, and Access behavior read-only. It does not authorize creating or changing a Cloudflare object. A missing or incorrect tunnel, route, DNS record, Access application, policy, certificate, or token is a stop condition requiring a focused amendment. See the Windows Development Machine Bootstrap.
Target architecture
flowchart LR
User["Approved developer\nbrowser + email OTP"]
Access["Cloudflare Access\nself-hosted applications"]
DNS["Cloudflare DNS\npublished hostnames"]
T1["anuva-machine1\nremote-managed tunnel"]
T2["anuva-machine2\nremote-managed tunnel"]
M1["Machine 1\nloopback services"]
M2["Machine 2\nloopback services"]
Canonical["anuva.girishd.com\ncanonical aggregate"]
User --> Access --> DNS
DNS --> T1 --> M1
DNS --> T2 --> M2
Access --> Canonical
Use one tunnel per machine. Never run both machines as replicas of the same tunnel: replicas are interchangeable origins, while the two Anuva machines may serve different working trees.
The tunnel configuration and hostname routes are remotely managed in Cloudflare.
cloudflared runs as an interactive Anuva-managed process rather than an
always-on Windows service. This is deliberate: working-tree previews should be
exposed only while the corresponding development session is active.
Ownership boundaries
| Concern | Owner |
|---|---|
| Domain, DNS, tunnel creation, routes, certificates | Cloudflare Dashboard |
| Access applications, identity provider, policies, sessions | Cloudflare Zero Trust Dashboard |
| Tunnel token creation and rotation | Cloudflare Dashboard plus the developer |
| Token file and non-secret machine configuration | Each Windows development machine |
| Local service startup, connector process, health checks, logs | Anuva CLI |
| MkDocs content and URL calculation | Repository docs and Anuva CLI |
| Canonical documentation build and push | Explicit anuva docs publish workflow |
The Anuva CLI must not create or delete tunnels, DNS routes, Access applications, policies, identity providers, certificates, or tunnel tokens.
Prerequisites
Before configuring a machine, confirm:
girishd.comis an active zone managed by Cloudflare DNS;- a Cloudflare Zero Trust organization exists;
- the approved developer email address is known;
cloudflaredis installed from an official Cloudflare distribution andcloudflared versionsucceeds;- each local origin can listen on
127.0.0.1at its configured port; and - outbound traffic to Cloudflare Tunnel endpoints on port
7844is permitted.
Certificate coverage
All Development preview routes use single-level hostnames under girishd.com,
such as main1.girishd.com and anuva2.girishd.com. This keeps them within the
normal *.girishd.com wildcard depth instead of requiring multi-level wildcard
coverage.
Before enabling the routes, confirm Cloudflare shows active edge-certificate coverage for every configured hostname. Do not bypass certificate validation or switch a route to plain public HTTP to work around a certificate problem.
Configure Cloudflare Access first
Create Access protection before publishing tunnel routes. A published application without an Access application is reachable from the Internet.
Enable email one-time PIN
The current Anuva login method is email OTP. New Cloudflare Zero Trust accounts do not add OTP automatically.
In the Cloudflare Dashboard:
- Go to Zero Trust > Integrations > Identity providers.
- Select Add new identity provider.
- Select One-time PIN and save it.
- Confirm the approved mailbox can receive mail from
noreply@notify.cloudflare.com.
Do not store email credentials or OTP codes in Anuva configuration or Codex chat.
Create the reusable allow policy
Create a reusable policy named Anuva solo developer:
| Field | Value |
|---|---|
| Action | Allow |
| Include selector | Emails |
| Value | The exact approved developer email address |
Do not use Everyone, Emails ending in for a public mail domain, or Login
Methods = One-time PIN. The last option accepts any valid OTP identity unless a
separate identity condition narrows it.
Test the exact email address with Cloudflare's policy tester before attaching the policy to applications.
Create Access applications
Create these self-hosted applications and attach the reusable allow policy:
| Application | Public hostname | Suggested session duration |
|---|---|---|
Anuva Development machine1 |
anuva1.girishd.com, main1.girishd.com, bento1.girishd.com, web1.girishd.com, python1.girishd.com, unity1.girishd.com |
24 hours |
Anuva Development machine2 |
anuva2.girishd.com, main2.girishd.com, bento2.girishd.com, web2.girishd.com, python2.girishd.com, unity2.girishd.com |
24 hours |
Anuva Canonical Docs |
anuva.girishd.com |
24 hours |
Add all six exact hostnames as public application domains for each Development
application. Do not replace them with *.girishd.com, which would also match the
canonical docs and unrelated first-level subdomains.
Use a shorter session if the device is shared or less trusted. Do not add Bypass policies for health checks or static assets. An unauthenticated Access redirect is a valid remote route-health result for CLI diagnostics.
Create one remotely managed tunnel per machine
In the Cloudflare Dashboard:
- Go to Networking > Tunnels.
- Create
anuva-machine1for Machine 1. - Create
anuva-machine2for Machine 2. - Do not add either machine as a replica of the other tunnel.
- Confirm each tunnel has its own UUID and token.
The dashboard may offer a Windows service-install command. Do not use the
always-on service for these Development tunnels. Install the cloudflared binary,
then let the Anuva CLI start the selected tunnel with its token file.
Store the tunnel token on Windows
A remotely managed tunnel token is a secret: anyone holding it can run a connector for that tunnel.
For each machine:
- Open the tunnel in Networking > Tunnels.
- Select Add a replica and copy the tunnel token from the generated command.
- Open PowerShell and create the secrets directory outside every Git repository:
- Open the Machine 1 token file in Notepad. This avoids putting the token in PowerShell history:
- Paste only the token as one line, without quotes, a variable name, or the
surrounding
cloudflaredcommand. Save and close Notepad. The path expands to:
On Machine 2, use cloudflared-anuva-machine2.token instead.
- Restrict the Machine 1 file ACL to the interactive Windows developer account and local administrators:
icacls "$env:LOCALAPPDATA\Anuva\secrets\cloudflared-anuva-machine1.token" /inheritance:r /grant:r "$($env:USERNAME):(R,W)" "Administrators:F"
- Run
icaclswith only the file path and confirm no other account or group has access. Delete any temporary clipboard or text-file copy used to transfer the token.
Do not put the token itself in %APPDATA%\Anuva\development.yaml, an environment
file, PowerShell command, Git, logs, issue descriptions, documentation, process
arguments, or Codex chat. Do not use Set-Content, echo, or another command that
would place the token in terminal history. The CLI receives only the token-file
path and invokes:
cloudflared version 2025.4.0 or later is required for --token-file.
Configure published application routes
For a full Cloudflare DNS setup, adding a published application route in the Dashboard also creates the required DNS record. Configure each route on its own machine tunnel and enable Protect with Access where the route UI provides it.
Machine 1 routes
| Public hostname | Service URL | Purpose |
|---|---|---|
anuva1.girishd.com |
http://127.0.0.1:3000 |
CMS Web development app |
main1.girishd.com |
http://127.0.0.1:4001 |
Product Main docs |
bento1.girishd.com |
http://127.0.0.1:4005 |
Bento docs |
web1.girishd.com |
http://127.0.0.1:4002 |
CMS docs |
python1.girishd.com |
http://127.0.0.1:4013 |
Python server docs |
unity1.girishd.com |
http://127.0.0.1:4004 |
Unity docs |
Machine 2 routes
| Public hostname | Service URL | Purpose |
|---|---|---|
anuva2.girishd.com |
http://127.0.0.1:3000 |
CMS Web development app |
main2.girishd.com |
http://127.0.0.1:4001 |
Product Main docs |
bento2.girishd.com |
http://127.0.0.1:4005 |
Bento docs |
web2.girishd.com |
http://127.0.0.1:4002 |
CMS docs |
python2.girishd.com |
http://127.0.0.1:4013 |
Python server docs |
unity2.girishd.com |
http://127.0.0.1:4004 |
Unity docs |
Do not publish PostgreSQL, the Python API, Unity control ports, Docker, remote desktop, file shares, or arbitrary local ports. The Web app talks to the Python server and database locally; those dependencies are not public Tunnel routes.
Run the Machine 1 connector manually
This is the current manual procedure until the Anuva CLI development-environment commands are implemented. Start the local origins that you want to expose first:
| Local origin | Expected route |
|---|---|
http://127.0.0.1:3000 |
https://anuva1.girishd.com |
http://127.0.0.1:4001 |
https://main1.girishd.com |
http://127.0.0.1:4005 |
https://bento1.girishd.com |
http://127.0.0.1:4002 |
https://web1.girishd.com |
http://127.0.0.1:4013 |
https://python1.girishd.com |
http://127.0.0.1:4004 |
https://unity1.girishd.com |
In PowerShell, verify the installed version and start the connector:
cloudflared version
cloudflared tunnel run --token-file "$env:LOCALAPPDATA\Anuva\secrets\cloudflared-anuva-machine1.token"
Keep that PowerShell window open while the Development environment is in use.
Stop the connector with Ctrl+C.
Run only one connector command for the machine. The token identifies the remotely
managed anuva-machine1 tunnel, and cloudflared receives all published route
mappings assigned to that tunnel from Cloudflare. Do not run one connector per
hostname and do not run cloudflared tunnel route dns for routes already created
in the Dashboard.
After startup:
- Open Networking > Tunnels >
anuva-machine1and confirm the tunnel is Healthy. - Confirm all six Machine 1 published application routes are assigned to this tunnel.
- Open each HTTPS hostname and confirm Cloudflare Access challenges an unauthenticated request.
- Authenticate and confirm each route shows the intended local application or documentation site.
The connector can be Healthy while an individual route returns a Cloudflare
502. That normally means its mapped local origin is stopped, unhealthy, or
listening on a different port; it does not require another tunnel process.
Machine-local Anuva configuration
Store non-secret configuration at %APPDATA%\Anuva\development.yaml:
schemaVersion: 1
machine: machine1
devRoot: C:\\Anuva\\dev
tunnel:
name: anuva-machine1
tokenFile: C:\\Users\\<user>\\AppData\\Local\\Anuva\\secrets\\cloudflared-anuva-machine1.token
services:
webapp:
repository: anuvax-cms
port: 3000
url: https://anuva1.girishd.com
docs:
anuva-main-video-creator: { port: 4001, url: https://main1.girishd.com }
anuva-bento: { port: 4005, url: https://bento1.girishd.com }
anuvax-cms: { port: 4002, url: https://web1.girishd.com }
anuva-python-server: { port: 4013, url: https://python1.girishd.com }
anuva-unity-video-creator: { port: 4004, url: https://unity1.girishd.com }
Machine 2 uses machine2, anuva-machine2, its token-file path, and the
corresponding anuva2, main2, bento2, web2, python2, and unity2
hostnames. The YAML contains the secret file path, not the secret value.
Start and stop behavior
The normal entry points are:
anuva dev start --with-docs --with-tunnel
anuva dev start --docs-only --with-tunnel
anuva dev status --json
anuva dev logs cloudflared
anuva dev stop --all --confirm
On start, the CLI must:
- verify
cloudflaredand its minimum version; - validate the configured tunnel name and absolute token-file path;
- verify that the token file exists and is readable without printing its content;
- start the required loopback origins;
- start one fingerprinted
cloudflaredprocess with--token-file; - verify local origins before checking their public hostnames;
- accept an Access
302or login page as proof that an unauthenticated route is alive; and - return safe URLs, PIDs, health, and log locations without credentials.
The CLI must not attempt to automate OTP login. Authenticated content verification remains a user/browser action unless a separate service-auth design is approved.
On stop, terminate only the connector and services started and fingerprinted by
the current Anuva environment. Do not stop an unrelated cloudflared process or
delete any Cloudflare resource.
Verification checklist
Run this checklist independently on both machines:
- [ ]
cloudflared versionmeets the documented minimum. - [ ] The configured token file exists outside Git and its contents never appear in logs.
- [ ] All expected origins respond on
127.0.0.1before the tunnel starts. - [ ] The correct tunnel becomes Healthy in Networking > Tunnels.
- [ ] Every published hostname reaches the Cloudflare Access login flow when unauthenticated.
- [ ] The exact approved email receives an OTP and can authenticate.
- [ ] A different email does not receive access.
- [ ] Authenticated pages show content from the intended machine and repository.
- [ ] No origin is reachable through a machine LAN address solely because of this setup.
- [ ] Stopping the Anuva environment disconnects the connector and leaves Dashboard resources intact.
- [ ]
anuva.girishd.comremains Access-protected and independent of both machine tunnels.
Troubleshooting
| Symptom | Likely cause | Check |
|---|---|---|
| Tunnel is Inactive or Down | Connector not running, invalid token, or blocked egress | Token file, process log, outbound port 7844 |
Cloudflare 502 |
Route is healthy but the local origin is down or has the wrong port | Loopback URL and Dashboard service URL |
| DNS name does not resolve | Published route or DNS record is missing | Tunnel Routes and Cloudflare DNS |
| Browser reports certificate mismatch | Edge certificate is not active for the hostname | Edge Certificates and the exact published hostname |
| Access login is not shown | Access application does not match the hostname or a Bypass exists | Application hostname and policies |
| OTP is never delivered | Email is not explicitly allowed or mail scanning/filtering interferes | Reusable policy, OTP IdP, allowed sender |
| Correct login shows the wrong working tree | Hostname is routed to the wrong tunnel or the machines share a tunnel | Route-to-tunnel mapping and tunnel UUID |
CLI remote check reports 302 |
Expected unauthenticated Access challenge | Authenticate in a browser for content verification |
Do not weaken Access, add a public bypass, expose a LAN listener, or create a shared cross-machine tunnel merely to clear a health check.
Token rotation and machine retirement
Rotate a tunnel token immediately if it appears in a log, screenshot, issue, repository, command argument, or chat transcript.
For planned rotation:
- Stop the affected Anuva environment.
- Rotate the token in the Cloudflare Dashboard.
- replace the local token file without changing its ACL;
- restart the environment and verify every route; and
- confirm the previous token no longer connects.
When retiring a machine, stop its connector, revoke its token, remove its published routes and Access application after review, then delete the tunnel. These are manual Cloudflare operations and are outside normal Anuva CLI scope.