Help with creating a router

Hey, just wondering where the latest guides would be for setting up via docker compose.

I've not messed with ziti for a while, well over a year so my config will probably be outdated so I wanted to set it all up from scratch.

I think I have a controller up and running via docker compose but now need to get a router up at the same node (a cloud hosted vm)

I have the controller running with

[root]# cat compose.yml

volumes:
  ziti-controller:
    driver: local

networks:
  ziti:
    driver: bridge

services:
  chown-controller:
    image: busybox
    command: chown -R ${ZIGGY_UID:-2171} /ziti-controller
    volumes:
      - ziti-controller:/ziti-controller

  ziti-controller:
    image: ${ZITI_CONTROLLER_IMAGE:-openziti/ziti-controller}
    depends_on:
      chown-controller:
        condition: service_completed_successfully
    user: ${ZIGGY_UID:-2171}
    volumes:
      - ziti-controller:/ziti-controller
    networks:
      ziti:
        aliases:
          - ${ZITI_CTRL_ADVERTISED_ADDRESS:-ziti-controller}
    # assign override vars in an .env file or export from parent env to ensure consistency throughout the compose
    # project
    environment:
      # *** these are the important vars to set to bootstrap the configuration during first run***
      ZITI_CTRL_ADVERTISED_ADDRESS: ${ZITI_CTRL_ADVERTISED_ADDRESS:-ziti-controller}  # FQDN of the controller
      ZITI_CTRL_ADVERTISED_PORT: ${ZITI_CTRL_ADVERTISED_PORT:-1280}                   # TCP port of the controller
      ZITI_PWD: ${ZITI_PWD:-}                                                         # password for the default admin user

      # *** less relevant vars below ***
      ZITI_BOOTSTRAP: true             # bootstrap the controller if "true"
      ZITI_BOOTSTRAP_PKI: true         # make the default PKI if "true"; requires ZITI_BOOTSTRAP=true
      ZITI_BOOTSTRAP_CONFIG: true      # make config file from env vars and defaults if "true," overwrite if "force"; requires ZITI_BOOTSTRAP=true
      ZITI_BOOTSTRAP_DATABASE: true    # make the default admin user if "true"; requires ZITI_BOOTSTRAP=true
      ZITI_AUTO_RENEW_CERTS: true      # renew certs automatically every startup; requires ZITI_BOOTSTRAP_PKI=true
      ZITI_BOOTSTRAP_CONFIG_ARGS:      # additional arguments to: ziti create config controller

    command: run config.yml
    ports:
      # ensure this port matches the value of ZITI_CTRL_PORT in the container
      - ${ZITI_INTERFACE:-0.0.0.0}:${ZITI_CTRL_ADVERTISED_PORT:-1280}:${ZITI_CTRL_ADVERTISED_PORT:-1280}
    expose:
      - ${ZITI_CTRL_ADVERTISED_PORT:-1280}
    restart: unless-stopped
    healthcheck:
      test:
        - CMD
        - ziti
        - agent
        - stats
      interval: 3s
      timeout: 3s
      retries: 5
      start_period: 15s

and env

ZITI_CTRL_ADVERTISED_ADDRESS=ziti-controller.wizznet.co.uk
ZITI_CTRL_ADVERTISED_ADDRESS=ziti-controller.wizznet.co.uk
ZITI_CTRL_EDGE_ADVERTISED_ADDRESS=ziti-controller.wizznet.co.uk
ZITI_CTRL_EDGE_IP_OVERRIDE=10.60.0.120
ZITI_BOOTSTRAP=true
ZITI_BOOTSTRAP_PKI=true
ZITI_USER=admin
ZITI_PWD=password
ZITI_BOOTSTRAP_CONFIG=true
ZITI_BOOTSTRAP_DATABASE=true
ZITI_AUTO_RENEW_CERTS=true

I then tried to create a router but struggling.

I first did this to create a jwt (after logging into controller)

ziti edge create edge-router contabo-router --jwt-output-file contabo-router.jwt

then a config

ziti create config router edge --routerName contabo-router

Now its at this point where I'm a bit unsure of how to use all this in another docker compose for the router, I've tried a few combinations using snippets of what I'm finding online and can't seem to get anything to work.

Any ideas of how to proceed with the router?

Thanks!

Jon.

Hi again @bodleytunes, the latest doc for docker is under deployments here Deploying with Docker | OpenZiti

Were you able to find the compose file referenced? ziti/dist/docker-images/ziti-router/compose.yml at main ยท openziti/ziti ยท GitHub

I don't know if there's one compose file that ties both together and I think @qrkourier will be out for a few days but he should be back next week. He's more familiar with these and will probably be able to help better.

1 Like

Thanks I'll take a look!
Jon.

Hi,

I tried that latest compose file and used my generated jwt token for ZITI_ENROL_TOKEN in the .env but it doesn't seem to like it and complains.

And I generated the token for router on the controller with

ziti edge create edge-router contabo-router2 --jwt-output-file contabo-router.jwt

Whoops typo! ZITI_ENROL_TOKEN :melting_face:

Getting further now:

","msg":"tproxy config: udpIdleTimeout   =  [5m0s]","time":"2025-05-19T10:28:17.393Z"}
ziti-router-1   | {"file":"github.com/openziti/ziti/tunnel/intercept/tproxy/tproxy_linux.go:103","func":"github.com/openziti/ziti/tunnel/intercept/tproxy.New","level":"info","msg":"tproxy config: udpCheckInterval =  [30s]","time":"2025-05-19T10:28:17.393Z"}
ziti-router-1   | {"error":"netlink receive: operation not permitted","file":"github.com/openziti/ziti/tunnel/intercept/tproxy/tproxy_linux.go:108","func":"github.com/openziti/ziti/tunnel/intercept/tproxy.New","level":"error","msg":"unable to add 100.64.0.1/10 to lo","time":"2025-05-19T10:28:17.394Z"}
ziti-router-1   | {"error":"failed to initialize tproxy interceptor: netlink receive: operation not permitted","file":"github.com/openziti/ziti/router/xgress_edge_tunnel/factory_wrapper.go:159","func":"github.com/openziti/ziti/router/xgress_edge_tunnel.NewFactoryWrapper.func2","level":"fatal","msg":"error starting","time":"2025-05-19T10:28:17.394Z"}
ziti-router-1 exited with code 0

Also added these to the router container thinking it might be network related permissions

    cap_add:
      - NET_ADMIN
      - NET_RAW
      - SYS_ADMIN
    security_opt:
      - apparmor=unconfined

managed to get it to run now but had to disable tproxy mode and change it to host in the config file in the docker volume.

I notice my router is showing as online but not as public. How can I change this to public without re-enrolling and starting everything from scratch?

Seems I'm getting that tproxy error even on my local new tunneller/router which is running in an lxc container (in docker again). I might try a privileged lxc container next to see if that makes any difference.

However, the contabo server I tried on earlier above is a VM running in the cloud so still really baffled as to how to get tproxy working on that.

I think I need tproxy at the local end because im looking to intercept some udp traffic for a docker service and send it down the tunnel to a remote headend at the contabo server.

I'm going to be using the sidecar trick with the network_mode:ziti-tunnel

Got my local router up now, just need to sort this tproxy stuff? :thinking: :face_with_spiral_eyes:

ziti edge list edge-routers

โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ ID        โ”‚ NAME               โ”‚ ONLINE โ”‚ ALLOW TRANSIT โ”‚ COST โ”‚ ATTRIBUTES โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Yk0KxGqfw โ”‚ contabo-router2    โ”‚ true   โ”‚ true          โ”‚    0 โ”‚            โ”‚
โ”‚ lDOk2cqTY โ”‚ local-router-lsk15 โ”‚ true   โ”‚ true          โ”‚    0 โ”‚            โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

Hi @bodleytunes,

Looks like you got it working without my help! That's great. You're now looking to intercept some traffic within docker so that you can use the router to intercept traffic. I assume you have other containers that you're looking to have access to the overlay, right?

Yes you'll need to figure out the tproxy stuff and you'll need to figure out how to declare a container as another container's network. If you're interested this video https://www.youtube.com/watch?v=odMy4F_iPdU or this discourse post Add new service on a separate "green" network in docker compose quickstart have similar information and yes they demonstrate using network_mode.

I think you're on the right track!

1 Like

One more thing, I was trying to create a Zac console, manually, and I don't think I'm using the right certs for it.

I created an admin identity then did ops unwrap on the json file and used the generated .key and .cert files in the env var for Zac console but it doesn't start it says it still looking for certificates so I don't think its the right type of cert?

[root]# docker compose up
[+] Running 1/1
 โœ” Container openziti-web-console-ziti-console-1  Created                      0.0s
Attaching to ziti-console-1
ziti-console-1  | waiting for server key to exist...
ziti-console-1  | waiting for server key to exist...

Do I need to generate intermediate ones or something? If so what would the command be for that?

Cheers,
Jon.

OK those certs did work in the end just had to copy them to the correct location so they were mounted to the container

  ziti-console:
      - ZAC_SERVER_CERT_CHAIN=/persistent/pki/certs/jon.cert
      - ZAC_SERVER_KEY=/persistent/pki/keys/jon.key

full compose

[root]# cat compose.yml
services:

  ziti-console:
    image: openziti/zac
    working_dir: /usr/src/app
    environment:
      #- ZAC_SERVER_CERT_CHAIN=/persistent/pki/${ZITI_CTRL_EDGE_ADVERTISED_ADDRESS:-ziti-edge-controller}-intermediate/certs/${ZITI_CTRL_EDGE_ADVERTISED_ADDRESS:-ziti-edge-controller}-server.cert
      #- ZAC_SERVER_KEY=/persistent/pki/${ZITI_CTRL_EDGE_ADVERTISED_ADDRESS:-ziti-edge-controller}-intermediate/keys/${ZITI_CTRL_EDGE_ADVERTISED_ADDRESS:-ziti-edge-controller}-server.key
      - ZAC_SERVER_CERT_CHAIN=/persistent/pki/certs/jon.cert
      - ZAC_SERVER_KEY=/persistent/pki/keys/jon.key
      - ZITI_CTRL_EDGE_ADVERTISED_ADDRESS=${ZITI_CTRL_EDGE_ADVERTISED_ADDRESS:-ziti-edge-controller}
      - ZITI_CTRL_EDGE_ADVERTISED_PORT=${ZITI_CTRL_EDGE_ADVERTISED_PORT:-1280}
      - ZITI_CTRL_NAME=${ZITI_CTRL_NAME:-ziti-edge-controller}
      - ZAC_CONTROLLER_URLS=${ZAC_CONTROLLER_URLS:-ziti-edge-controller:1280}
      - PORTTLS=8443
    ports:
      - ${ZITI_INTERFACE:-0.0.0.0}:8443:8443
    volumes:
      - ./ziti-fs:/persistent

Hey it's great you got it working! That's not exactly the way i would have generated those certs, myself. I would have suggested you use the ziti pki command along with the root ca from the controller container.

i also would recommend you deliver the ZAC from the controller, on the same API as the management API (then there's no new certs to generate). Is there any reason you wanted a separate container? Maybe you have a good reason for wanting another container, instead of delivering it from the controller? Or perhaps it wasn't clear that you could do that?

1 Like

I'm not sure really I just wanted to spin things up separately so I could understand a bit more what's going on in the background.

Just need to sort the tproxy stuff now, if I fix it will report back.

OK update, I noticed that the relavent kernel modules were not even loaded on my proxmox server, so I loaded them. I then made the lxc container privileged but still seem to have the same tproxy errors.

The mystery continues.

Think I'm getting somewhere.

Really strange results

Added a netshoot container as a service along with the router, made it share same network ns

then docker exec'd into netshoot and ran ip addr add 100.64.0.5/10 dev lo and it works and can see the ip address.

But, if docker exec'ing into the ziti router container if I try and run same type of commands I get operation not permitted.

[ziggy@9d958b0bde5a ~]$ ip addr add 100.64.0.10/10 dev lo
RTNETLINK answers: Operation not permitted

I'm getting this because its running it as "ziggy" and ziggy doesn't have permissions.

Would this also affect the router service? How to give it root permissions?