NetFoundry Console vs Customer Connect

Same use case — accessing company services via your identity — shown step by step in both UIs.

📖 Use Case: Employee accesses internal company services from their laptop

💻 Your Laptop
Ziti Desktop Edge
already running
──▶
🌐 Zero Trust Fabric
Ziti Network
──▶
🖥️ Company Server
192.168.1.x
──▶
⚙️ CRM App
TCP:8080
+
🗄️ Database
TCP:5432

Two internal services running on company servers. You want to access them securely from your laptop — no VPN, no open firewall ports.

🔧 NetFoundry Console 12 manual steps · Ziti expertise required

Network → Edge Routers → Service (CRM) → Service (DB) → Server Identity → Bind Policy → ER Policy (server) → Employee Identity → Dial Policy → ER Policy (employee) → Distribute JWTs manually → Employee enrolls

✨ Customer Connect 6 steps · No Ziti knowledge needed

Add Location → Gateway Connector (CRM) → Gateway Connector (DB) → Create Connection → Invite User by email → Install agent on server → Employee enrolls from email

What CC auto-creates on every action

When you save a Connector
CC auto-creates in Ziti:
  • Ziti Identity (for the tunneler agent)
  • Ziti Service (per application / port)
  • Bind Service Policy (tunneler ↔ service)
  • Edge Router Policy (tunneler)
  • Enrollment JWT (shown in Setup tab)
When you save a Connection
CC auto-creates in Ziti:
  • Dial Service Policy (user ↔ services)
  • Edge Router Policy (user identity)
  • zitiName = networkId|name|dial
When you invite a User
CC auto-creates in Ziti:
  • Ziti Identity for the employee
  • Enrollment JWT sent via invitation email
  • RBAC role grant (Admin / Read-Only)
The underlying Ziti objects are identical to what you'd create manually in the NetFoundry console — same gateway.production.netfoundry.io API, just generated automatically.
🔧 NetFoundry Console Low-level / Manual
Step 1 — Network Setup
1

Create / select a Network manual

Go to Networks → Create Network. Choose a region for the controller.

Network name Region
2

Deploy Edge Routers manual

Add hosted or customer-managed Edge Routers to the network so identities can connect.

Must do this before any services or identities can talk to each other.
Step 2 — Define Services (server side)
3

Create Service — CRM App manual

Services → New Service. Configure intercept (what clients see) and host (where traffic goes).

Name: Company CRM Intercept: TCP / port 8080 Host: 192.168.1.10:8080
Intercept config = what Ziti Desktop Edge intercepts on the client side.
Host config = where the tunneler on the server forwards to.
4

Create Service — Database manual

Repeat the above for the database service.

Name: Company DB Intercept: TCP / port 5432 Host: 192.168.1.20:5432
Step 3 — Server Identity & Tunneler
5

Create Identity — server tunneler manual

Identities → New Identity. This identity runs ziti-edge-tunnel on the server and BINDS (hosts) the services.

Name: server-tunneler-01 Type: Device
Download the enrollment JWT — one-time-use token, expires in 24h.
6

Install & Enroll tunneler on server manual

SSH into the company server. Install ziti-edge-tunnel, then enroll using the JWT.

ziti-edge-tunnel enroll --jwt <token>
Tunneler is now online and can bind (host) services on behalf of the server.
7

Create Bind Service Policy manual

Policies → New Service Policy. Type = Bind. Links the server tunneler identity to the services it hosts.

Type: Bind Identity: #server-tunneler-01 Services: #company-crm, #company-db
8

Create Edge Router Policy (server) manual

Links the server tunneler identity to the Edge Routers it can use.

Identity: #server-tunneler-01 Edge Routers: #all
Step 4 — Employee Identity
9

Create Identity — employee manual

Identities → New Identity. This identity is for the employee's laptop (Ziti Desktop Edge).

Name: john.doe@company.com Type: Device
Download the enrollment JWT and send it to the employee.
10

Create Dial Service Policy manual

Policies → New Service Policy. Type = Dial. Grants the employee identity permission to access the services.

Type: Dial Identity: #john.doe Services: #company-crm, #company-db
11

Create Edge Router Policy (employee) manual

Links the employee identity to the Edge Routers it can use.

Identity: #john.doe Edge Routers: #all
12

Employee enrolls in Ziti Desktop Edge manual

Employee opens Ziti Desktop Edge → Add Identity → paste JWT token from step 9.

Once enrolled, Ziti Desktop Edge intercepts traffic to company-crm and company-db automatically.
✨ Customer Connect Console High-level / Automated
Pre-done by Provider (one-time)
—

Network + Edge Routers auto by provider

Provider already provisioned the Ziti network and deployed Edge Routers. You never touch these.

This is what the Provider Setup wizard does — customers inherit it.
Step 1 — Add Location (server side)
1

Add a Location

Setup → Location Details → Add Location. Represents the site where your company servers live.

Name: Company Server Room Address / region
Step 2 — Add Connectors (replaces: Services + Server Identity + Bind Policy)
2

Add Gateway Connector — CRM App auto

Add Connector → Gateway. Point it at the CRM service. Add the application config.

Type: Gateway Name: CRM Access Target: 192.168.1.10 Port: 8080
CC auto-creates behind the scenes:
→ Ziti Service (intercept + host config)
→ Ziti Identity for the server tunneler
→ Bind Service Policy (tunneler ↔ service)
→ Edge Router Policy for tunneler
3

Add Gateway Connector — Database auto

Same as above for the database. Or add a second Application to the same connector if on the same server.

Type: Gateway Name: DB Access Target: 192.168.1.20:5432
Each connector gets its own Ziti identity + bind policy automatically.
Step 3 — Create Connection (replaces: Dial Policy + Edge Router Policy)
4

Create a Connection auto

Setup → Connections → Add Connection. Link the employee user to both connectors.

Name: Employee Access Source: john.doe (user identity) Destination: CRM Access, DB Access
CC auto-creates behind the scenes:
→ Ziti Dial Service Policy (employee ↔ services)
→ Edge Router Policy for employee identity
Step 4 — Invite Employee (replaces: Create Identity + send JWT)
5

Invite User by Email auto

Setup → Users → Invite. Enter employee email + role.

Email: john.doe@company.com Role: Admin or Read-Only
CC auto-creates a Ziti Identity for the employee and sends an enrollment email — no manual JWT download or distribution needed.
Step 5 — Save & Deploy
6

Save Customer

Deployment Summary → Save Customer. Progress bar shows each resource being created on the API.

7

Install connector agent on server

Go to the connector's Setup tab → copy the install command → SSH into the server and run it.

Ziti tunneler install + enrollmentJwt embedded
The connector shows as Online in the dashboard once enrolled. This is the ziti-edge-tunnel enroll step from NF Console, but the JWT is pre-filled.
8

Employee enrolls in Ziti Desktop Edge

Employee gets an invitation email. Opens Ziti Desktop Edge → Add Identity → uses the token from the email.

Same Ziti Desktop Edge you already use — no change to the client. The only difference is the enrollment token comes by email instead of from the console.
What Customer Connect creates automatically in Ziti
You configure in NetFoundry Console Customer Connect equivalent What CC auto-creates in Ziti
Network Edge Routers Provider Setup (done once by provider) Ziti Network + Hosted Edge Routers — pre-provisioned, customers never touch these.
Service
(intercept config + host config)
Connector + Application
(Gateway/Host type + target IP:port)
Connector.zitiName = providerId|locationId|name
One Ziti Service per Application on the Connector. Application.zitiServiceId
Identity (server tunneler)
Bind Service Policy
Edge Router Policy (tunneler)
Connector created
(all three auto-created)
Ziti Identity for the tunneler (Connector.zitiId)
Bind Service Policy → tunneler binds the service
Edge Router Policy → tunneler can reach all ERs
Identity (employee)
Dial Service Policy
Edge Router Policy (employee)
Invite User + Create Connection Ziti Identity for the user (identityId)
Dial Service Policy (ApiConnection.zitiName = networkId|name|dial)
Edge Router Policy for the user identity
Enrollment JWT
(downloaded manually, emailed manually)
Connector Setup tab
User invitation email
Connector.enrollmentJwt — shown in Setup tab with install command
User enrollment JWT — sent automatically via invitation email
What exactly is a Connector?
Part 1 — Configuration (in CC)
The logical record stored in Customer Connect

When you create a Connector in the UI, CC saves a record with: name, type, location, target IP:port, allowed applications. It also auto-creates the Ziti Identity, Service, and Bind Policy behind the scenes.

At this point the connector exists in the database but is Offline / Not Enrolled — nothing is running on the server yet.
Part 2 — Software (on your server / VM)
The agent you install on the machine hosting the service

The Setup tab shows the install command with the enrollment JWT pre-filled. Run it on the server — the software registers with the Ziti fabric and the connector turns Online.

You need both. Configuration without software = Offline. Software without configuration = nothing to enroll.
Software installed per connector type
Type Software installed on server/VM Use when…
Host ziti-edge-tunnel (Ziti tunneler) Service runs on localhost of the same machine the agent is on
Gateway ziti-edge-router (Ziti Edge Router) Service runs on a different machine reachable by IP from where the agent is installed
Clientless ziti-edge-router with special config Browser-based access via a public domain — end user needs no client app at all
SDK Embedded OpenZiti SDK linked into your application Your app is the connector — no separate agent install needed
Lifecycle
① Create in CC UI
CC creates Ziti Identity + Service + Bind Policy
Status: Not Enrolled
→
② Copy command from Setup tab
Install command with enrollmentJwt pre-filled
Status: Not Enrolled
→
③ Run on server / VM
Software installs + enrolls using the JWT, connects to Ziti fabric
Status: Online ✓
→
④ Traffic flows
Connector forwards traffic from Ziti fabric to the target service. No firewall ports needed.
Service accessible ✓

NetFoundry Console — you manually create:

  • 1 Network
  • Edge Routers (hosted or customer-managed)
  • 2 Services (one per internal app)
  • 1 Server Identity (tunneler)
  • 1 Bind Service Policy
  • 1 Edge Router Policy (server)
  • 1 Employee Identity
  • 1 Dial Service Policy
  • 1 Edge Router Policy (employee)
  • Manually download & distribute JWTs

≈ 10–12 manual steps, Ziti expertise required

Customer Connect — you configure:

  • 1 Location
  • 2 Gateway Connectors (one per service)
  • 1 Connection (access policy)
  • 1 User invite (by email)
  • Run install command on server
  • Employee enrolls from invitation email


≈ 6 steps, no Ziti expertise needed — all Ziti objects created automatically

The end result is identical

The same Ziti Network, Services, Identities, Bind/Dial Policies, and Edge Router Policies exist either way.
Customer Connect just creates them automatically when you save — using the same NetFoundry API at gateway.production.netfoundry.io.

Real-world Use Case — XYZ-Motor-Corp
🏢
XYZ-Motor-Corp admin
Sets everything up in CC
☁️
AWS EC2 Instance
Hosts the internal service (port 8080)
👤
James (Employee)
Needs access from laptop — has Ziti Desktop Edge
🎯
Goal
James accesses XYZ Web App on EC2 — no VPN, no open AWS security groups
CC Setup Wizard — Admin configures
1
Login & Customer Details
Admin logs into CC. First-time setup wizard starts with customer details.
Organisation: XYZ-Motor-Corp Branding: optional
2
Add Location 1 — Server side (AWS EC2)
Represents the AWS environment where the service runs.
Name: AWS Production Cloud: AWS Region: us-east-1
3
Add Location 2 — Client side (James's laptop)
Represents where James and other employees work from. Needed to place the Device connector that will be the Source in the Connection.
Name: Employee Workstations Physical / remote
This step was missing in the original flow. Without a client-side location you cannot place a Device connector for James, and the Connection has no valid Source.
4
Add Connector 1 — Service side (Host connector on EC2) DESTINATION
This is the server side. Installs ziti-edge-tunnel on the EC2. Forwards traffic to the service running locally.
Name: XYZ-Production-Connector Type: Host Location: AWS Production
Hosted Application
App: XYZ Web App Protocol: TCP Listen: 8080 Forward: 127.0.0.1:8080
CC auto-creates: Ziti Identity (EC2 agent) · Ziti Service (XYZ Web App TCP:8080) · Bind Policy · Edge Router Policy · Enrollment JWT
5
Add Connector 2 — Client side (Device connector for James) SOURCE
This is the client side. Represents James's laptop. Type = Device — installs ziti-edge-tunnel (or Ziti Desktop Edge) on the laptop. No applications needed — Device connectors dial out, they don't host services.
Name: James-Laptop Type: Device Location: Employee Workstations
CC auto-creates: Ziti Identity (James's laptop tunneler) · Edge Router Policy · Enrollment JWT → shown in Setup tab
This step was missing. Without this Device connector there is no valid Source for the Connection — as seen in the screenshot where "AWS Production" (the server location) was incorrectly placed as the Source.
6
Create Connection — James-Employee-Access
Now both sides exist. Wire the Source (client) → Destination (server).
Source — who dials
James-Laptop (Device)
Employee Workstations location
→
Destination — what hosts
XYZ-Production-Connector (Host)
AWS Production location
Name: James-Employee-Access App: XYZ Web App
CC auto-creates: Dial Service Policy (James-Laptop → XYZ Web App) · Edge Router Policy (James)
7
Invite James — CC portal access
Gives James a login to the CC portal. Separate from the Device connector enrollment above.
Email: james@xyz-motor-corp.com Role: Read-Only
CC auto-creates: CC portal identity for James · RBAC role grant (Read-Only)
8
Save Customer
Deployment Summary → Save Customer. All Ziti objects are created on the NetFoundry API in sequence. Dashboard opens when done.
Post-save — Install & Enroll
9
Install Host connector agent on EC2
Dashboard → XYZ-Production-Connector → Setup tab → copy command → SSH into EC2 and run.
curl -s https://get.openziti.io/tun/scripts/install-linux.bash | bash
ziti-edge-tunnel enroll --jwt <token-from-XYZ-Production-Connector-setup-tab>
XYZ-Production-Connector shows Online. EC2 is now hosting XYZ Web App on the Ziti fabric.
10
Enroll James-Laptop Device connector on his laptop
Dashboard → James-Laptop → Setup tab → copy the enrollment JWT → James opens Ziti Desktop Edge on his laptop → Add Identity → paste the token.
James-Laptop connector shows Online. James's laptop is now the active dialing endpoint.
✓
James accesses the service
James opens localhost:8080 in his browser. Ziti Desktop Edge intercepts the traffic and tunnels it through the fabric to the EC2.
No VPN. No open AWS security groups. No firewall rules. The connection goes through the Zero Trust fabric — James's identity is verified on every request.
What CC created automatically in Ziti
Host Connector (EC2 — Destination)
  • Ziti Identity — EC2 agent
  • Ziti Service — XYZ Web App (TCP:8080)
  • Bind Service Policy
  • Edge Router Policy
  • Enrollment JWT → Setup tab
Device Connector (Laptop — Source)
  • Ziti Identity — James's laptop
  • Edge Router Policy
  • Enrollment JWT → Setup tab
Connection + User Invite
  • Dial Service Policy (laptop → XYZ Web App)
  • Edge Router Policy (dialer)
  • CC portal identity for James
  • RBAC grant (Read-Only)

The end result is identical

The same Ziti Network, Services, Identities, Bind/Dial Policies, and Edge Router Policies exist either way.
Customer Connect just creates them automatically when you save — using the same NetFoundry API at gateway.production.netfoundry.io.

Troubleshooting
Commands used during this session
Check service status sudo systemctl status ziti-edge-tunnel
View full service logs sudo journalctl -u ziti-edge-tunnel -n 30 --no-pager
List identity files sudo ls -la /opt/openziti/etc/identities/
Find identity file if misplaced sudo find /opt/openziti /root /home -name "*.json" 2>/dev/null
Move identity to correct dir sudo mv /home/ubuntu/<identity>.json /opt/openziti/etc/identities/
Fix ownership sudo chown ziti:ziti /opt/openziti/etc/identities/<identity>.json
Fix permissions sudo chmod 660 /opt/openziti/etc/identities/<identity>.json
Restart service sudo systemctl restart ziti-edge-tunnel
ziti-edge-tunnel commands
Check version ziti-edge-tunnel version
Enroll using JWT string sudo ziti-edge-tunnel enroll --jwt "<paste-jwt>" --identity /opt/openziti/etc/identities/connector.json
Enroll using downloaded .jwt file sudo ziti-edge-tunnel enroll --jwt /path/to/connector.jwt --identity /opt/openziti/etc/identities/connector.json
Run manually (foreground, debug) sudo ziti-edge-tunnel run --identity-dir /opt/openziti/etc/identities --verbose=debug
List loaded identities (via socket) sudo ziti-edge-tunnel dump -p /var/run/ziti-edge-tunnel.sock
Add identity to running service sudo ziti-edge-tunnel add-identity -i /opt/openziti/etc/identities/connector.json
🔴
Connector shows Enrolled + Offline after installing the agent
The CC console marks a connector Enrolled as soon as the enrollment JWT is consumed. Offline means the ziti-edge-tunnel service is not currently connected to the Ziti fabric — typically because the identity file is missing, in the wrong location, or has incorrect permissions.
Cause 1 — Install and Enroll are separate steps

The curl … | bash command only installs the ziti-edge-tunnel binary and starts the service. It does not enroll the identity. The service starts and watches /opt/openziti/etc/identities/ — if no .json identity file is there, it runs idle and the connector stays Offline.

Symptom in service logs: Loading identity files from /opt/openziti/etc/identities followed by silence — no identity loaded line.
Fix — run the enrollment command explicitly, pointing output to the identities directory:
sudo ziti-edge-tunnel enroll \
  --jwt "<paste-jwt-from-CC-Setup-tab>" \
  --identity /opt/openziti/etc/identities/connector.json
sudo systemctl restart ziti-edge-tunnel
Cause 2 — Identity file enrolled but saved to the wrong location

If you ran ziti-edge-tunnel enroll without the --identity flag, the resulting .json file may have been written to the current working directory (e.g. /home/ubuntu/) instead of the identities directory the service watches.

Diagnose — check where the identity file landed:
sudo ls -la /opt/openziti/etc/identities/
# If empty or only config.json, search elsewhere:
sudo find /opt/openziti /root /home -name "*.json" 2>/dev/null
Fix — move the file into the identities directory:
sudo mv /home/ubuntu/your-identity.json /opt/openziti/etc/identities/
sudo systemctl restart ziti-edge-tunnel
Cause 3 — Identity file has wrong ownership / permissions

If the identity file was created or moved while running as a different user (e.g. ubuntu), the ziti-edge-tunnel service (which runs as the ziti user) cannot write to it for certificate renewal.

Symptom in service logs (startup script): WARN: identity file '…json' is not writable so it cannot be renewed
Fix — set correct ownership and restart:
sudo chown ziti:ziti /opt/openziti/etc/identities/your-identity.json
sudo chmod 660 /opt/openziti/etc/identities/your-identity.json
sudo systemctl restart ziti-edge-tunnel
After a successful restart the service log shows loading identity file: your-identity.json and the connector flips to Online in the CC console within ~60 seconds.