Skip to main content
Star OpenZiti on GitHub Star

Router Deployment

Deploy a router as a Linux system service. The router introduction may help to read first.

  1. Creation
  2. Installation
  3. Configuration
  4. Starting Up

Router creation

Create the router in the controller first with the web console or the CLI.

After creating the router, save the enrollment token (JWT) for the configuration step below.

Install the router package

The router package provides a systemd service unit and bootstrapping script.

One-liner install script

Use the install script to configure the package repo and install the ziti CLI (if not already done):

curl -sS https://get.openziti.io/install.bash | sudo bash -s openziti

Then install openziti-router in a terminal session so the bootstrap can prompt you.

sudo apt-get install openziti-router     # Debian, Ubuntu
sudo dnf install openziti-router # RedHat, Fedora

For non-interactive installs, see Automation.

Manual package repo setup

Configure the package repository and install openziti-router.

Configure the repository for the Debian family of distributions (Ubuntu, Mint, Pop!_OS)

Install the OpenZiti repository key.

curl -sSLf https://get.openziti.io/tun/package-repos.gpg | sudo gpg --dearmor --output /usr/share/keyrings/openziti.gpg

Ensure the key is readable by all users.

sudo chmod a+r /usr/share/keyrings/openziti.gpg

Create the repository file.

sudo tee /etc/apt/sources.list.d/openziti-release.list >/dev/null <<EOF
deb [signed-by=/usr/share/keyrings/openziti.gpg] https://packages.openziti.org/zitipax-openziti-deb-stable debian main
EOF

Update the package list.

sudo apt update

Finally, install the package: openziti-router

The openziti package provides the ziti CLI and is installed as a dependency.

Configuration

You need a config file and an enrollment with the controller. The easiest way to get both is to run the bootstrap script. You can also migrate from an existing installation or craft a config by hand. The bootstrap script is a convenience — it is not required.

Run the bootstrap script

sudo /opt/openziti/etc/router/bootstrap.bash

The script creates a config file and enrolls the router with the controller. It prompts for answers interactively. When run non-interactively (e.g., with an answer file), it uses the provided values without prompting.

On success, the script enables and starts the service.

The script asks for:

  • Permanent external address — DNS name or IP of this router (required, no default)
  • Port — TCP port (default: 3022)
  • Enrollment token — the JWT from the controller (as a string or file path)

Migrate an existing configuration

This example illustrates copying the configuration and identity files from a previous installation.

Craft a configuration

Create a config file directly with ziti create config router edge --routerName=router. Run ziti create config environment to see the available environment variables. See the router configuration reference for details.

Automation

If you're scripting deployments or using configuration management, you can supply answers ahead of time and run the bootstrap script without prompts. You can also choose which components to bootstrap.

How to supply answers

Answers can come from any combination of:

  • Answer file — copy /opt/openziti/etc/router/bootstrap.env as a template, fill in the values, and pass it as the first argument. The bootstrap script reads the file but never modifies it.
  • Environment — export answers as environment variables and pass them with sudo -E

Precedence (highest to lowest): environment variables → answer file → service.env defaults.

Answers are written to a temporary file during bootstrap and deleted automatically on success. If bootstrap fails, the temporary file is preserved and a re-run command is printed.

cp /opt/openziti/etc/router/bootstrap.env /tmp/my-answers.env
# edit /tmp/my-answers.env with your values
sudo -E /opt/openziti/etc/router/bootstrap.bash /tmp/my-answers.env

Router answers

  1. ZITI_ROUTER_ADVERTISED_ADDRESS — permanent external address of this router (required)
  2. ZITI_ROUTER_PORT — TCP port (default: 3022)
  3. ZITI_ENROLL_TOKEN — enrollment token as a string or file path (required)

Selective bootstrapping

You don't have to bootstrap everything at once. Each component can be enabled or disabled independently in /opt/openziti/etc/router/service.env:

AnswerDefaultWhat it does
ZITI_BOOTSTRAP_CONFIGtrueGenerate config.yml (set to force to regenerate)
ZITI_BOOTSTRAP_ENROLLMENTtrueEnroll with the controller (set to force to re-enroll)

Starting up

The bootstrap script automatically enables and starts the service on success. If you need to start it manually (for example, after crafting a configuration by hand):

sudo systemctl enable --now ziti-router.service

Further configuration

Customize /var/lib/ziti-router/config.yml as needed and restart the service.

sudo systemctl restart ziti-router.service

Here's a link to the configuration reference.

Learn more about managing routers with the CLI.

Customize the systemd service

Use systemctl edit to override service directives like capabilities or the startup command. Pass -E to sudo so your shell's SYSTEMD_EDITOR (or EDITOR / VISUAL) is used.

sudo -E systemctl edit ziti-router.service
sudo systemctl restart ziti-router.service

The package includes a drop-in file with commented example directives at /etc/systemd/system/ziti-router.service.d/override.conf. Your edits to this file are preserved across package upgrades.

Firewall

The router's generated configuration uses a single TCP port (default: 3022).

Confirm the router is listening:

sudo ss -tlnp | grep ziti
Output
LISTEN 0      4096                          *:3022             *:*    users:(("ziti",pid=2166302,fd=8))

Troubleshooting

Controller address override

The router learns the controller's address from the enrollment token, so you don't normally need to supply it. If you need to override the address in the enrollment token, supply these answers via the answer file or environment variables:

  • ZITI_CTRL_ADVERTISED_ADDRESS — controller DNS name or IP address
  • ZITI_CTRL_ADVERTISED_PORT — controller port (default: 1280)

For Ziti versions 1.6 and lower, both answers are required.

Verify edge listener

Verify the edge listener is reachable by identities. The edge listener must terminate TLS for identities because they will authenticate with a client certificate for all interactions.

The server certificate must be issued by the controller's edge signer CA (edge.enrollment.signerCert in the controller's config.yml).

Substitute the value of listeners[?binding == 'edge'].options.advertise from /var/lib/ziti-router/config.yml:

openssl s_client -connect {listeners[?binding == 'edge'].options.advertise} -alpn ziti-edge -showcerts <>/dev/null \
|& openssl storeutl -certs -noout -text /dev/stdin \
| grep -E '(Subject|Issuer):'
Output
Issuer: C=US, L=Charlotte, O=NetFoundry, OU=ADV-DEV, CN=NetFoundry Inc. Intermediate CA 42KvRQxn.
Subject: C=US, ST=NC, L=Charlotte, O=NetFoundry, OU=Ziti, CN=BhCjN2Rkx
Issuer: C=US, L=Charlotte, O=NetFoundry, OU=ADV-DEV, CN=NetFoundry Inc. Certificate Authority IpcOEkAR6
Subject: C=US, ST=NC, L=Charlotte, O=NetFoundry, OU=ADV-DEV, CN=NetFoundry Inc. Intermediate CA 42KvRQxn.

At least one router must provide a link listener if you have multiple routers. Verify all link listeners are reachable by all routers. The link listener must terminate TLS for routers because they will authenticate with a client certificate for all interactions.

The server certificate must be issued by the controller's edge signer CA (edge.enrollment.signerCert in the controller's config.yml).

Substitute the value of link.listeners[?binding == 'transport'].advertise after the tls: prefix from /var/lib/ziti-router/config.yml:

openssl s_client -connect {link.listeners[?binding == 'transport'].advertise} -alpn ziti-link -showcerts <>/dev/null \
|& openssl storeutl -certs -noout -text /dev/stdin \
| grep -E '(Subject|Issuer):'
Output
Issuer: C=US, L=Charlotte, O=NetFoundry, OU=ADV-DEV, CN=NetFoundry Inc. Intermediate CA 42KvRQxn.
Subject: C=US, ST=NC, L=Charlotte, O=NetFoundry, OU=Ziti, CN=BhCjN2Rkx
Issuer: C=US, L=Charlotte, O=NetFoundry, OU=ADV-DEV, CN=NetFoundry Inc. Certificate Authority IpcOEkAR6
Subject: C=US, ST=NC, L=Charlotte, O=NetFoundry, OU=ADV-DEV, CN=NetFoundry Inc. Intermediate CA 42KvRQxn.

Logging

View the service's output.

journalctl -u ziti-router.service

Set a different format in the ZITI_ARGS environment variable and restart the service.


ZITI_ARGS='--log-formatter text'


Learn more in the logging reference.

Uninstall

  1. Clean the service state.

    sudo systemctl disable --now ziti-router.service
    sudo systemctl reset-failed ziti-router.service
    sudo systemctl clean --what=state ziti-router.service
  2. Purge the package, including configuration files.

    APT - Debian, Ubuntu, etc.

    sudo apt-get purge openziti-router

    RPM - RedHat, Fedora, etc.

    sudo dnf remove openziti-router
  3. Remove any firewall exceptions you created.