The Problem with Open Ports
My SSH logs used to be a mess. Every morning, I’d scroll through hundreds of failed login attempts from botnets located in corners of the globe I’ve never even visited. My standard routine involved opening a port, configuring Nginx, and praying that Fail2Ban would catch the bad actors. After six months of running OpenZiti, those logs are finally silent. I haven’t touched a firewall rule in half a year, yet my services are more accessible than ever.
Traditional security relies on the ‘castle and moat’ model. You build a thick wall (the firewall) but leave a gate open for Port 443 or 22. The issue is simple: if a port is open for you, it’s open for everyone. OpenZiti flips the script. It creates ‘dark’ services that don’t listen on a public IP at all. Instead, they reach out to a secure fabric. If Shodan or Nmap scans your IP, they see nothing but a digital brick wall.
Comparing Approaches: Traditional VPN vs. OpenZiti
Before making the jump, I relied on WireGuard. It’s fast, but it still requires one side of the tunnel to have a reachable, public-facing UDP port. If someone finds that port, you’re still a target for DDoS attacks. OpenZiti removes that ‘listening’ requirement entirely.
| Feature | Traditional VPN (WireGuard) | OpenZiti (Zero Trust) |
|---|---|---|
| Inbound Ports | Required (UDP/TCP) | Zero (Outbound only) |
| Access Control | Network-wide (IP-based) | Granular (Identity-based) |
| Attack Surface | Reduced | Eliminated (Dark) |
| Resource Usage | Very Low | Low (~50MB RAM for tunnelers) |
Lessons from Six Months in Production
The Wins
- Zero Log Spam: My auth logs are actually readable now. Since there is no public port 22 exposed, I’ve seen a 100% reduction in brute-force attempts.
- True Least Privilege: I can give a contractor access to a specific PostgreSQL instance on port 5432 without letting them touch anything else on the server.
- Network Agility: My laptop connects the same way whether I’m on my home fiber or a spotty coffee shop Wi-Fi. The connection is tied to a cryptographic identity, not a transient IP address.
The Hurdles
- Conceptual Shift: You have to stop thinking about IP addresses and start thinking about Services and Identities. It took me about four days to stop reflexively reaching for
iptables. - PKI Management: Managing certificates and keys is the backbone of the system. If you lose your controller’s root CA, you’re in for a long afternoon of rebuilding.
Recommended Setup Architecture
For a reliable ‘stealth’ network, I suggest a three-tier approach:
- The Controller: This acts as the air traffic control for your network. It manages identities and enforces policies. I run mine on a $5/month VPS.
- The Edge Router: This is the entry point to your fabric. For small setups, you can host this on the same VPS as the controller.
- The Tunneler: A lightweight agent (ziti-edge-tunnel) that runs on your server and your client devices.
When I provisioned my Ziti Controller, I used the password generator at toolcraft.app/en/tools/security/password-generator to create high-entropy admin keys. Since it generates strings locally in the browser, it’s a safe way to handle the complex credentials required for the database and admin accounts without risking network exposure.
Implementation: Setting Up Your Stealth Network
We’ll use the ‘Express Install’ method. It’s the most straightforward path for Ubuntu 22.04 or 24.04 LTS users.
Step 1: Install the OpenZiti CLI
Grab the management tools first. Run this on your intended controller server:
curl -sS https://get.openziti.io/install.sh | sudo bash
export PATH=$PATH:$HOME/.ziti/bin
Step 2: Launch the Fabric
The Quickstart script automates the tedious certificate generation and routing setup. It’s a massive time-saver.
# Use your server's public DNS or IP
export ZITI_CTRL_ADVERTISED_ADDRESS=ziti.yourdomain.com
source /dev/stdin <<< "$(curl -sS https://get.openziti.io/quickstart/express-install.sh)"
Save the admin credentials the script spits out. You’ll need them to manage the network later. This command spins up both the Controller and an Edge Router automatically.
Step 3: Creating Identities
Next, we need two digital passports: one for your application server and one for your laptop.
# Authenticate with the controller
ziti edge login $ZITI_CTRL_ADVERTISED_ADDRESS:1280 -u $ZITI_USER -p $ZITI_PWD
# Create the identities
ziti edge create identity device app-server-node -o app-server.jwt
ziti edge create identity user my-laptop -o laptop.jwt
The .jwt files are one-time enrollment tokens. Securely move app-server.jwt to your server and laptop.jwt to your workstation.
Step 4: Hiding the App Server
On the server you want to protect, install the tunneler. This agent creates an outbound-only connection to the fabric. No inbound firewall rules are needed.
sudo apt update && sudo apt install ziti-edge-tunnel
# Enroll the device
sudo ziti-edge-tunnel enroll --jwt app-server.jwt --identity /var/lib/ziti/app-server.json
Step 5: Defining the Service
This is where we map the connectivity. We’re telling OpenZiti that a service exists on the ‘app-server-node’ (locally on port 8080), but we want our laptop to see it as internal.dashboard.ziti.
# Create the service entry
ziti edge create service my-private-app
# Define where the app lives (The Bind)
ziti edge create config app-host.v1 host.v1 '{"protocol":"tcp", "address":"localhost", "port":8080}'
# Define how the client accesses it (The Intercept)
ziti edge create config app-client.v1 intercept.v1 '{"protocols":["tcp"], "addresses":["internal.dashboard.ziti"], "portRanges":[{"low":80, "high":80}]}'
# Apply the access policies
ziti edge create service-policy app-bind Bind --identity-roles "#app-server-node" --service-roles "#my-private-app"
ziti edge create service-policy app-dial Dial --identity-roles "#my-laptop" --service-roles "#my-private-app"
Testing the Stealth Connection
Install the OpenZiti Desktop Edge on your laptop and import your laptop.jwt. Now, open your browser and head to http://internal.dashboard.ziti.
It feels like magic, but it’s just smart routing. Your server’s firewall is still blocking every single inbound connection. If you try to scan the server’s public IP, it will appear as if the server isn’t even online. Yet, your browser loads the dashboard instantly.
Switching to OpenZiti has fundamentally changed my security posture. By removing the ‘front door’ to my servers, I’ve eliminated a whole category of automated attacks. It takes more effort than a basic SSH tunnel, but the peace of mind is worth the 15-minute setup.

