cf-managed-network-endpoint

cf-managed-network-endpoint

Docker app from Tomjoad's Repository

Overview

TLS endpoint for Cloudflare Zero Trust "Managed Networks". Serves a self-signed certificate on port 6443; the Cloudflare WARP client compares its SHA-256 fingerprint to tell whether a device is on the home network. No application logic. The certificate is created once, on the very first start, and kept in the Config folder (keys/). As long as that folder survives, the fingerprint stays the same across restarts and image updates. NEVER delete it: a new certificate means a new fingerprint, and network detection breaks silently. Include the appdata folder in your backups. The fingerprint is printed in the container log on every start (Unraid: container icon -> Logs). Upgrading from a version before 1.0.0: keep the old /certs path below for the first start, so the existing certificate is taken over. Then remove it. Network: a custom VLAN interface (e.g. br0.10) must exist on the machine; set a static IP outside the DHCP pool in this container's "Fixed IP address" setting.

cf-managed-network-endpoint

TLS endpoint for Cloudflare Zero Trust "Managed Networks".

The container serves a self-signed TLS certificate on port 6443. The Cloudflare WARP client (Cloudflare One client) connects to it and compares the certificate's SHA-256 fingerprint to detect whether a device is on your home network. There is no application logic: the HTTP answer (200, plain text) does not matter, only the TLS handshake does.

Built on linuxserver.io's baseimage-alpine-nginx (s6-overlay, non-root abc user, docker mods).

⚠️ Fingerprint stability (the important part)

Network detection breaks silently when the fingerprint changes. Therefore:

  • The certificate is not baked into the image and not regenerated at every start.
  • On start, an init step looks for cert.crt and cert.key in /config/keys. If both exist, they are used. If neither exists, a pair is created once (RSA 2048, 3650 days, CN=managed-network.internal).
  • /config must be a persistent volume. As long as it survives, the fingerprint survives restarts, image rebuilds and updates.
  • Never delete the volume. The next start would create a new certificate with a new fingerprint, and Cloudflare would need the new value. Include the appdata folder in your backups.
  • If only one of the two files exists, the container aborts with an error instead of silently creating a new pair.

Parameters

Parameter Function
-p 6443 TLS port. With a custom VLAN interface the container listens on its own IP and no port mapping is needed.
-e PUID=1000 User ID that owns the key pair.
-e PGID=1000 Group ID that owns the key pair.
-e UMASK=022 Permissions mask for new files (optional).
-e TZ=Etc/UTC Time zone for the log, see the list of tz names (optional).
-v /config Key pair in keys/ (cert.crt, cert.key) and nginx config in nginx/. Never delete.

The nginx site is /config/nginx/site-confs/default.conf; edit it there to change the answer or the TLS settings.

Reading the fingerprint

1. Container log (easiest): every start prints it prominently. In Unraid: container icon → Logs.

==================================================================
 SHA-256 fingerprint of the TLS certificate

   AB:CD:...

 For Cloudflare Zero Trust (managed networks, without colons):

   abcd...
==================================================================

2. In the running container:

docker exec cf-managed-network-endpoint \
  openssl x509 -in /config/keys/cert.crt -noout -fingerprint -sha256

3. Over the network:

openssl s_client -connect <STATIC-IP>:6443 </dev/null 2>/dev/null \
  | openssl x509 -noout -fingerprint -sha256

Cloudflare expects the value without colons (the log prints both).

Deployment on Unraid

Target environment (adapt to your network):

Parameter Value
Network own VLAN, subnet <SUBNET> (e.g. 10.0.0.0/24)
Static IP <STATIC-IP> (outside the DHCP pool)
Gateway <GATEWAY>
Docker network custom VLAN interface br0.<VLAN-ID> (not bridge)
Port 6443 (TLS)
Config /mnt/user/appdata/cf-managed-network-endpoint → /config

Option A — Unraid template: copy unraid/cf-managed-network-endpoint.xml to /boot/config/plugins/dockerMan/templates-user/, then Add Container → choose the template and set the static IP under "Fixed IP address". Unraid manages restarts itself; don't add --restart to Extra Parameters.

Option B — docker run:

docker run -d \
  --name cf-managed-network-endpoint \
  --network br0.<VLAN-ID> \
  --ip <STATIC-IP> \
  -e PUID=99 -e PGID=100 -e UMASK=002 \
  -v /mnt/user/appdata/cf-managed-network-endpoint:/config \
  --restart unless-stopped \
  ghcr.io/tom-joad/cf-managed-network-endpoint:latest

Don't add --init: the base image's /init (s6-overlay) must be PID 1.

Upgrading from a version before 1.0.0

Older versions kept the key pair in a /certs volume. To keep the fingerprint, mount the old folder at /certs as well (read-only is fine) together with the new /config for the first start:

  -v /mnt/user/appdata/cf-managed-network-endpoint:/config \
  -v /mnt/user/appdata/cf-managed-network-endpoint/certs:/certs:ro \

If /config/keys is empty, the certificate is copied over once and the log shows the same fingerprint as before. Compare it with the value in Cloudflare. Afterwards /certs can be removed. The old folder is never modified.

Configuring Cloudflare Zero Trust

  1. Copy the fingerprint from the container log (format without colons).
  2. Zero Trust dashboard → Settings → WARP Client → Network locations → Managed networks → Add new managed network.
  3. Type TLS, host <STATIC-IP>, port 6443, enter the SHA-256 fingerprint.
  4. Use the managed network as a condition in your WARP device profiles (for example a profile for "home network detected").

The WARP client checks reachability on every network change. To test: bring a device onto the home network and watch the device profile switch.

Development

docker build -t cf-managed-network-endpoint .
tests/smoke.sh cf-managed-network-endpoint   # health, certificate, fingerprint stability
docker run -d --name cfmne-test -p 6443:6443 -v cfmne-config:/config cf-managed-network-endpoint
curl -k https://localhost:6443/              # -> 200 "cf-managed-network-endpoint"
docker logs cfmne-test                       # fingerprint

CI (.github/workflows/build-and-push.yml) runs the smoke test and gitleaks on every push and pull request. For v* tags it builds a multi-arch image (linux/amd64, linux/arm64) with SBOM and provenance, scans it with Trivy, signs it with cosign and pushes it to ghcr.io/tom-joad/cf-managed-network-endpoint (tags: latest, sha-…, semver).

See SECURITY.md to report a vulnerability and CHANGELOG.md for changes.

Related apps

Explore more like this

Explore all

Details

Repository
ghcr.io/tom-joad/cf-managed-network-endpoint:latest
Last Updated2026-10-05
First Seen2026-10-05

Runtime arguments

Network
br0
Shell
sh
Privileged
false

Template configuration

ConfigPathrw

Holds the key pair (keys/) and the nginx config. NEVER delete it: a new certificate means a new fingerprint and Cloudflare network detection breaks.

Target
/config
Default
/mnt/user/appdata/cf-managed-network-endpoint
Old certificate volume (upgrade only)Pathro

Only when upgrading from a version before 1.0.0: your old .../certs folder, read once to take over the certificate. Remove afterwards.

Target
/certs
PUIDVariable

User that owns the key pair (nobody)

Default
99
PGIDVariable

Group for the key pair (users)

Default
100
UMASKVariable

Permissions mask for new files

Default
002
TZVariable

Time zone for the log, e.g. Europe/Berlin

Default
Etc/UTC