I've been using Zrok for a longtime, and I have tried with success the terminal app. I've tried the docker install for another service and worked, and it's cleaner as I have Docker running for those services. The problem is that I want to run more than one service in the docker install and I'm not able to figure how to set it up.
I would be able to add more services in the future
Hi @Delfi_r, welcome to the community and to zrok (and OpenZiti)!
Generally speaking there's no way to share multiple services on one install. You can run one zrok share container for each service to expose.
Did you also find this other discourse post that covers the same topic?
There's also a feature request: Single Command, Multiple Share|Access · Issue #194 · openziti/zrok · GitHub to enable this sort of functionality on the roadmap.
1 Like
I use zrok on a Mac. On this machine I run different prototype services on different ports. As you have explained I need to set up different pairs .env and compose.yml and compose up each of them so I'll end with different zrok images. I need to rename them different and take care on something in the compose.yml file?
Yes. You should be able to just run multiple containers, each container hosting a separate zrok share
process, as long as you are careful with naming those containers.
Me personally, I would just use the same .env file. You would want different compose files though because you'll be sharing different shares, yes. Depending on how good you are with docker and how you're running zrok, you might be able to keep the compose file the same but alter the env file. Overall, sounds like you're on the right path though.
i can't use the same .env file as this is where the name of the share is defined and yse, I want to share different services so i'll try to use the same docker compose file and try to get different containers. I'll inform you when all is done
1 Like
Thanks for sharing your issues and progress on this! Which approach are you using to enable the zrok environment for each share container? The two main approaches are these:
- Docker bind volume like
~/.zrok:/.zrok
and run-as user $UID
- Docker named volume like
zrok_env:/mnt
and env STATE_DIRECTORY=/mnt
The difference is that the first one uses the Docker host user's zrok environment, and the second one manages a separate zrok environment in Docker, separate from the Docker host user.
The first one is a little simpler and more immediate, whereas the second is more like a production service.
With either approach, I think you will find a way to re-use the same zrok environment for all the share containers.
Here's the docs with complete examples and tutorials for both approaches: Getting Started with Docker | Zrok
Before I try I'll want to ask another question because perhaps it's very important
I'm following Docker Compose Public Share | Zrok
I want to expose within Docker four services:
OpenWebhui running on localhost:3000 (now I use a reserved share with a terminal window)
Searxng running on localhost:4000 (now I use a reserved share with a terminal window)
Trasformer.lab on localhost:8000
Those will be on docker creating three .env files and composing three Docker containers. I'll try this, But I need first get a solution for a more complex project:
Perplexica has the front-end on 3080 (from the original 3000 all projects configure by default)
But the backend is running on localhost 3001. so I've figured I need a Caddyfile to set up a Reverse proxy:
your_zrok_share.zrok.io {
tls off # zrok already provides TLS/SSL, so we disable it here
reverse_proxy / localhost:3080 {
header_up Upgrade $http_upgrade
header_up Connection $http_connection
}
reverse_proxy /api/* localhost:3001 {
to {path}
}
reverse_proxy /ws/* localhost:3001 {
to {path}
websocket
}
}
My doubts are: I need to reserve a zrok.io share out of this file or it will be created when I compose the Docjer file?
Where I need to put the caddy file to create a docker container for it? Wich is the right thing to do?
Great. That sounds like it will work well with zrok and Docker.
You're following the Docker public share guide which uses a separate zrok env for the container, not the zrok environment belonging to the Docker host user.
Your compose environment needs the variables mentioned in that guide you linked.
ZROK_ENABLE_TOKEN=abcd123
ZROK_BACKEND_MODE=caddy
ZROK_TARGET=/Caddyfile
ZROK_UNIQUE_NAME=your_zrok_share
In the Docker public share compose.yml, you must mount the Caddyfile in the same path specified as the target, e.g.
services:
zrok-share:
volumes:
- ./Caddyfile:/Caddyfile
Your Caddyfile must follow the zrok documentation example with bind {{ .ZrokBindAddress }}
.
http:// {
bind {{ .ZrokBindAddress }}
reverse_proxy / localhost:3080 {
header_up Upgrade $http_upgrade
header_up Connection $http_connection
}
reverse_proxy /api/* localhost:3001 {
to {path}
}
reverse_proxy /ws/* localhost:3001 {
to {path}
websocket
}
}
The Docker public share compose.yml has everything inside to reserve your_zrok_share
and you will see the share appear in the web console when you do docker compose up
. Then you can visit https://your_zrok_share.share.zrok.io
Thanks a lot for your detailed reply. A simple question: how to name the caddyfile and were to put it?
You can name it Caddyfile
and put it in the same directory as compose.yml
to mount it in the container like this. Ensure the file is readable by setting permissive filemode on the Docker host.
chmod -c a+r ./Caddyfile
services:
your_zrok_share:
image: ${ZROK_CONTAINER_IMAGE:-docker.io/openziti/zrok}
restart: unless-stopped
entrypoint: zrok-share.bash
depends_on:
zrok-enable:
condition: service_completed_successfully
volumes:
- zrok_env:/mnt
- ./Caddyfile:/Caddyfile
environment:
ZROK_UNIQUE_NAME: "your_zrok_share"
ZROK_BACKEND_MODE: caddy
ZROK_TARGET: /Caddyfile
STATE_DIRECTORY: /mnt # zrok homedir in container
You can have many share containers like this, each mounting the zrok_env volume to provide the enabled environment.
Today I'm unable to set up a simple proxy Zrok service on docker, zrok is running on the console. After many retries, the share is visible on the Zrok web console but the service is not running to the target.
What I see now that if I put the .env and compose files on a folder called ZROK2 the container is named ZROK2 so it will be easy to set up many containers
I suspect the zrok share container couldn't reach the zrok controller, backend target, or both.
You'll have many zrok environments this way, one for each share, which may not be what you want. You can instead use a single zrok environment with many share containers by following the YAML snippet for "your_zrok_share" as an example.
Here's the concept: in your compose project, have one zrok-enable
container that enables the zrok environment. Mount the same volume from zrok-enable
on each share container in the same path, with STATE_DIRECTORY
env var set to the mountpoint. The shares will use the same environment. You can add numerous shares in the same compose file this way, or use separate files in the same compose project.
I've been playing with this idea today as I'm also interested in multiple shares in a single environment from a single docker compose stack/swarm/instance/[insert proper term here].
What I'm showing here doesn't relate directly to the OP's question, but it's in the ballpark and might be interesting to some.
As a starting point, I used the compose file from here. Using the extends
feature of docker compose, you can write a kind of zrok share template service and then use it to declare a service for each share in your compose file.
With the following two files in the same directory, try docker compose up
.
Note services zrok-share-1
and zrok-share-2
and the use of extends
.
compose.yaml
services:
zrok-init:
image: busybox
# matches uid:gid of "ziggy" in zrok container image
command: chown -Rc 2171:2171 /mnt/.zrok
user: root
volumes:
- zrok_env:/mnt/.zrok
# enable zrok environment
zrok-enable:
image: ${ZROK_CONTAINER_IMAGE:-docker.io/openziti/zrok}
depends_on:
zrok-init:
condition: service_completed_successfully
entrypoint: zrok-enable.bash
volumes:
- zrok_env:/mnt
environment:
STATE_DIRECTORY: /mnt
ZROK_ENABLE_TOKEN:
ZROK_API_ENDPOINT:
ZROK_ENVIRONMENT_NAME: docker-private-share
zrok-share-1:
extends:
file: zrok-share.yaml
service: zrok-share
environment:
ZROK_TARGET: 'http://localhost:8001'
zrok-share-2:
extends:
file: zrok-share.yaml
service: zrok-share
environment:
ZROK_TARGET: 'http://localhost:8002'
volumes:
zrok_env:
networks:
default:
zrok-share.yaml
services:
zrok-share:
image: ${ZROK_CONTAINER_IMAGE:-docker.io/openziti/zrok}
restart: no
entrypoint:
- bash
- -euxc
- |
env
echo "DEBUG: HOME=$${HOME}"
ls -lA /mnt/.zrok/
exec zrok share private --headless --backend-mode proxy "$${ZROK_TARGET}"
depends_on:
zrok-enable:
condition: service_completed_successfully
volumes:
- zrok_env:/mnt
environment:
HOME: /mnt
PFXLOG_NO_JSON: "true"
Note: In the zrok-share.yaml
, I wasn't able to find a way to get ${ZROK_TARGET}
to resolve when it's used in the command
element unless it's present in the .env
file (which defeats the purpose). I think that the command
element is resolved at compose file parse time, but variables specified in the environment
element are not available for resolution at that point. This is why the whole zrok
command is spelled out in the entrypoint
element.
2 Likes
Very cool. I hadn't stumbled upon extends
until now.