Illustrative Access, Tunnel and Origin concept in a WIUNIX Academy security studio

WIUNIX ACADEMY

Set up Cloudflare Tunnel and Access for a private web app on Ubuntu and Debian

Publish a private web app through an outbound tunnel and identity policy. Keep tokens protected, isolate the origin, verify denied access and retain a recovery path.

Intermediate50 min readUpdated
Make this guide yours

YOUR SYSTEM. YOUR STEPS.

Where are you working?

Choose your OS and version. The prerequisites, commands and troubleshooting follow your environment.

Ubuntu 26.04 LTSReviewed against official documentation ·

USE YOUR OWN VALUES

Configure this tutorial

Set the example values for your environment; related explanations and copy panels update together. Never enter passwords, private keys or tokens. Values stay in this tab and are not sent to the server or share links. Check actual DNS, certificates and network policy before running commands.

Different IP addresses, domains or ports? Open the settings below, change the values and select “Apply to tutorial”, then copy the updated commands.

Set values for my environment8 editable values

THE OUTCOME

What will you have at the end?

A loopback-only web origin, protected connector credential and verified allowed/denied identity access.

01HTTPS · app.example.comUser browser
02Cloudflare AccessIdentity policy → outbound tunnel
03127.0.0.1:8080Same-host origin
Supported operating systems and versions

Reviewed2026-10-20. OS paths are documented, not full installations. Real isolated tests covered the exact loopback receiver, unprivileged systemd credential loading and backup/restore byte equality on kernel6.8/systemd255. No real Cloudflare account, edge tunnel, QUIC, DNS publication, IdP/MFA or allowed/denied identity test was performed; these are acceptance steps for your deployment. No production service, firewall or package changed.

Before you begin

  • Fresh amd64/arm64 systemd host, sudo access and an independent console.
  • Active Cloudflare zone, unused hostname, and permission to manage Access and a tunnel.
  • Allowed and non-allowed test identities, working DNS/approved egress and a protected token store.

A private web app, reached through an identity gate

Build a dedicated learning origin on the same host as cloudflared, publish app.example.com through a remotely managed tunnel, then prove both allowed and denied access. This is for Linux administrators familiar with DNS, systemd and an identity provider. Allow about 50 minutes plus DNS/certificate provisioning. Tunnel is transport; Access is authorization. Neither replaces application permissions or backups.

Understand the three trust boundaries

Browser HTTPS terminates at Cloudflare, Access evaluates the user, and an outbound encrypted tunnel reaches cloudflared. The final HTTP hop is exclusively host loopback at 127.0.0.1:8080. No router port-forward or public origin listener is created. Cloudflare handles application traffic and identity metadata: assess its terms, jurisdiction, service availability and your data requirements. This browser HTTP guide is not a general VPN, private subnet route, SSH or WARP deployment.

Set public examples before copying

Use a fresh, unused single-level hostname under a Cloudflare-managed zone. Change public settings here before copying any part. The fixed loopback address and platform port 7844 are safety/protocol invariants. 8080 and 20241 must be unused and different. Use new dedicated directories /srv/academy-origin, /etc/cloudflared-academy and /var/backups/academy-tunnel, none nested inside another or an existing application. Values and custom progress stay in sessionStorage in this tab/language/environment; default progress uses localStorage. Settings never travel in share links or to a configuration server. Your custom deployment is not a tested result. Never put tokens or passwords in this panel. Directory inputs must be absolute paths beginning with /, not home shortcuts. Nested marker paths are created under the dedicated document root; they must not collide with a directory.

01

LET’S BUILD

Check the fresh connector host

On the dedicated Linux host, retain console or independent SSH access. Stop if cloudflared or either tutorial unit already belongs to another workload. Inspect listeners and selected paths; do not overwrite existing files. This guide owns only its two specifically named units. Use an amd64/arm64 machine supported by the vendor package, correct time and working DNS.

Bash

Run at the location stated in this step

cat /etc/os-release
dpkg --print-architecture
timedatectl status
systemctl list-unit-files 'cloudflared*' 'academy-origin*'
sudo ss -lntup
sudo ls -ld '/srv/academy-origin' '/etc/cloudflared-academy' '/var/backups/academy-tunnel'
How do I know it worked?

Correct OS/architecture/time; no competing cloudflared or tutorial services, selected ports free, and selected directories absent. Missing-path errors are expected on a fresh host.

02

LET’S BUILD

Create Access before publishing any route

In Cloudflare One, configure your existing team and login method, then Access controls → Applications → Create new application → Self-hosted and private → Add public hostname. Set application name Academy private web, session duration 1 hour, and public hostname app.example.com covering the entire host, with no path restriction. Save an Allow policy selecting only a specific approved test identity/group. With an existing MFA-capable IdP, require MFA at that IdP. An email OTP proves mailbox possession; it is not a claim of MFA. Do not use Everyone, Bypass or Service Auth for this human browser exercise. Have one allowed and one non-allowed test identity. Review current account limits/plan before enabling anything that costs money.

How do I know it worked?

The saved Access application protects exactly app.example.com; an explicit narrow Allow rule exists before a tunnel route.

03

LET’S BUILD

Create a remotely managed tunnel

In the Cloudflare dashboard, Networking → Tunnels → Create Tunnel, create academy-web as a cloudflared connector. Leave it without a published route for now. Open Add a replica to obtain the connector token. Do not execute the suggested token-bearing service-install command. Keep the token in your protected credential store and insert only its value later in a protected editor. It allows another connector to join this tunnel, not a user to pass Access. No tunnel login certificate, account API key or locally managed JSON credential is needed for this workflow.

How do I know it worked?

academy-web exists with no route; its connector token is retained privately, not in shell history.

Explore all tutorials ↗