# Can I achieve something similar using Zrok instead of Ngrok? Possible?

**URL:** <https://openziti.discourse.group/t/can-i-achieve-something-similar-using-zrok-instead-of-ngrok-possible/3837>\
**Category:** General Questions\
**Created:** [January 27, 2025, 10:36am UTC](https://openziti.discourse.group/t/can-i-achieve-something-similar-using-zrok-instead-of-ngrok-possible/3837 "2025-01-27T10:36:28Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![krigeta](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/krigeta/32/3097_2.png) [@krigeta](https://openziti.discourse.group/u/krigeta)\
**Post date:** [January 27, 2025, 10:36am UTC](https://openziti.discourse.group/t/can-i-achieve-something-similar-using-zrok-instead-of-ngrok-possible/3837/1 "2025-01-27T10:36:28Z")

</div>

is it possible to do something like this but using Zrok?

code for ngrok:  
import os  
from pyngrok import ngrok  
from IPython.display import clear\_output, Javascript  
ngrok.kill()  
%cd /kaggle/working/program\_ml  
os.system(f"filebrowser -r /kaggle -p 9876 \> /dev/null 2\>&1 &")  
clear\_output()  
%load\_ext tensorboard  
%tensorboard --logdir logs --port 8077  
p\_tunnel = ngrok.connect(6969)  
t\_tunnel = ngrok.connect(8077)  
f\_tunnel = ngrok.connect(9876)  
clear\_output()  
print("Applio Url:", p\_tunnel.public\_url)  
print("Tensorboard Url:", t\_tunnel.public\_url)  
print("File Url:", f\_tunnel.public\_url)  
print("Save the link for later, this will take a while...")

!source /kaggle/tmp/.venv/bin/activate; python app.py

currently I am using this to run zrok:  
command = 'source /kaggle/tmp/.venv/bin/activate; python app.py'  
port = '6969'  
port\_t = '8077'  
port\_f = '9876'

# ------------------------

os.system(f"filebrowser -r /kaggle -p 9876 \> /dev/null 2\>&1 &")  
%load\_ext tensorboard  
%tensorboard --logdir logs --port 8077  
cmd = f'/kaggle/working/zrok/zrok share public [http://localhost](http://localhost):{port} --headless & /kaggle/working/zrok/zrok share public [http://localhost](http://localhost):{port\_t} --headless & {command}'  
get\_ipython().system(cmd)

My question is:

- Is there a better or more streamlined way to replicate what I'm doing with Ngrok but using Zrok instead?
- Are there any improvements I can make to this code to achieve similar functionality more efficiently?

---

<div class="post-metadata">

**Author:** ![michael.quigley](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/michael.quigley/32/1123_2.png) [@michael.quigley](https://openziti.discourse.group/u/michael.quigley)\
**Post date:** [January 28, 2025, 2:58pm UTC](https://openziti.discourse.group/t/can-i-achieve-something-similar-using-zrok-instead-of-ngrok-possible/3837/2 "2025-01-28T14:58:45Z")

</div>

The `ngrok.connect` function is replicating (in code) what the `zrok share public` command is doing. Unfortunately the zrok SDK does not (currently) have a single function you can call like that (from Python) to instantiate the reverse proxy in code.

To do the equivalent of `ngrok.connect` for zrok, you would need to call `zrok.share.CreateShare` and also open a network connection to the local resource. With those 2 network connections created (one to the zrok network, and another to the local resource), you would need to use 2 threads to read from one and write to the other, and then also the inverse (read from the other and write to the first).

There's an example in the Python SDK that shows how `CreateShare` and `zrok.listener` works:

> <https://github.com/openziti/zrok/blob/main/sdk/python/examples/pastebin/pastebin.py>

At some point in the future we can probably provide a single function call that can instantiate a full reverse proxy in Python code.

---

<div class="post-metadata">

**Author:** ![qrkourier](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/qrkourier/32/52_2.png) [@qrkourier](https://openziti.discourse.group/u/qrkourier)\
**Post date:** [January 29, 2025, 2:24pm UTC](https://openziti.discourse.group/t/can-i-achieve-something-similar-using-zrok-instead-of-ngrok-possible/3837/3 "2025-01-29T14:24:33Z")

</div>

There's [a new proxy package for the Py SDK](https://github.com/openziti/zrok/pull/846) coming in the next zrok release. It enables a Jupyter notebook to proxy a public or private share to a local target like this:

```python
# %%
! pip install zrok

# %%

import zrok
from zrok.proxy import ProxyShare

# %%

target_url = "http://127.0.0.1:8000/"
unique_name = "myuniquename" # a name to reuse each run or 'None' for random
share_mode = "public" # "public" or "private"
frontend = "public" # custom domain frontend or "public"

if unique_name.lower() == "none":
    unique_name = None

# %%

zrok_env = zrok.environment.root.Load() # Load the environment from ~/.zrok

proxy_share = ProxyShare.create(
    root=zrok_env,
    target=target_url,
    frontends=[frontend],
    share_mode=share_mode,
    unique_name=unique_name,
    verify_ssl=True # Set 'False' to skip SSL verification
)

# %%

if share_mode == "public":
    print(f"Access proxy at: {', '.join(proxy_share.endpoints)}")
elif share_mode == "private":
    print(f"Run a private access frontend: 'zrok access private {proxy_share.token}'")

proxy_share.run()

```

Link to proxy notebook example: [zrok/sdk/python/examples/proxy/proxy.ipynb at main · openziti/zrok · GitHub](https://github.com/openziti/zrok/blob/main/sdk/python/examples/proxy/proxy.ipynb)

Basic usage excerpt from [the proxy README](https://github.com/openziti/zrok/blob/main/sdk/python/examples/proxy/README.md):

```python
from zrok.proxy import ProxyShare
import zrok

# Load the environment
root = zrok.environment.root.Load()

# Create a temporary proxy share (will be cleaned up on exit)
proxy = ProxyShare.create(root=root, target="http://my-target-service")

# print the public URL
print(f"Access proxy at: {proxy.endpoints}")
proxy.run()

```

---

<div class="post-metadata">

**Author:** ![krigeta](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/krigeta/32/3097_2.png) [@krigeta](https://openziti.discourse.group/u/krigeta)\
**Post date:** [January 31, 2025, 6:24am UTC](https://openziti.discourse.group/t/can-i-achieve-something-similar-using-zrok-instead-of-ngrok-possible/3837/4 "2025-01-31T06:24:47Z")

</div>

wow, this seems amazing! Is there any way to use it now?

---

<div class="post-metadata">

**Author:** ![qrkourier](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/qrkourier/32/52_2.png) [@qrkourier](https://openziti.discourse.group/u/qrkourier)\
**Post date:** [January 31, 2025, 4:17pm UTC](https://openziti.discourse.group/t/can-i-achieve-something-similar-using-zrok-instead-of-ngrok-possible/3837/5 "2025-01-31T16:17:28Z")

</div>

It just dropped. Will you let me know how it works for you?

```bash
pip install zrok==0.4.47

```

---

<div class="post-metadata">

**Author:** ![krigeta](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/krigeta/32/3097_2.png) [@krigeta](https://openziti.discourse.group/u/krigeta)\
**Post date:** [February 1, 2025, 7:00am UTC](https://openziti.discourse.group/t/can-i-achieve-something-similar-using-zrok-instead-of-ngrok-possible/3837/6 "2025-02-01T07:00:33Z")

</div>

tried the code but got this:

```auto
---------------------------------------------------------------------------
FileNotFoundError Traceback (most recent call last)
<ipython-input-19-d49b02e43cb2> in <cell line: 2>()
      1 #
----> 2 zrok_env = zrok.environment.root.Load() # Load the environment from ~/.zrok
      3 
      4 proxy_share = ProxyShare.create(
      5 root=zrok_env,

/usr/local/lib/python3.10/dist-packages/zrok/environment/root.py in Load()
    112 if __rootExists():
    113 r.meta = __loadMetadata()
--> 114 r.cfg = __loadConfig()
    115 r.env = __loadEnvironment()
    116 else:

/usr/local/lib/python3.10/dist-packages/zrok/environment/root.py in __loadConfig()
    137 def __loadConfig() -> Config:
    138 cf = configFile()
--> 139 with open(cf) as f:
    140 data = json.load(f)
    141 return Config(

FileNotFoundError: [Errno 2] No such file or directory: '/root/.zrok/config.json'

```

I am using it on a kaggle notebook

---

<div class="post-metadata">

**Author:** ![qrkourier](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/qrkourier/32/52_2.png) [@qrkourier](https://openziti.discourse.group/u/qrkourier)\
**Post date:** [February 1, 2025, 4:17pm UTC](https://openziti.discourse.group/t/can-i-achieve-something-similar-using-zrok-instead-of-ngrok-possible/3837/7 "2025-02-01T16:17:38Z")

</div>

The Load() function loads your existing zrok user environment from ~/.zrok (or Windows equivalent) that you enabled on this device: [Getting Started | Zrok](https://docs.zrok.io/docs/getting-started#enabling-your-zrok-environment)

The error indicates it was unable to find the config.json file in your environment, so it's possible you need to enable a zrok user environment or perhaps there is a bug requiring a config.json file when it might not exist.

EDIT: I found the issue. The SDK requires a config.json file to exist, but it should not require it, only loading it if it exists. Workaround is to create the file by setting at least one configuration directive.

This will set the same value as the default, so it will not change behavior if you are missing a config.json file inside your enabled zrok user environment dir, e.g., `~/.zrok`.

```bash
zrok config set apiEndpoint https://api.zrok.io

```

---

<div class="post-metadata">

**Author:** ![krigeta](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/krigeta/32/3097_2.png) [@krigeta](https://openziti.discourse.group/u/krigeta)\
**Post date:** [February 9, 2025, 1:04pm UTC](https://openziti.discourse.group/t/can-i-achieve-something-similar-using-zrok-instead-of-ngrok-possible/3837/8 "2025-02-09T13:04:26Z")

</div>

after trying a lot I am not able to run it using the way you mentioned if possible may you write a code that can work in kaggle/colab notebook so share ports like 8188 and sometimes able to share multiple ports. that would be so helpful

---

<div class="post-metadata">

**Author:** ![qrkourier](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/qrkourier/32/52_2.png) [@qrkourier](https://openziti.discourse.group/u/qrkourier)\
**Post date:** [February 9, 2025, 5:44pm UTC](https://openziti.discourse.group/t/can-i-achieve-something-similar-using-zrok-instead-of-ngrok-possible/3837/9 "2025-02-09T17:44:10Z")

</div>

Sure thing, glad to help. Please help me understand the problem you encountered.

For example, if you are running a local webserver on 8188/TCP you can do this after you set at least one configuration with `zrok config set`.

```python
from zrok.proxy import ProxyShare
import zrok

# Load the environment
root = zrok.environment.root.Load()

# Create a temporary proxy share (will be cleaned up on exit)
proxy = ProxyShare.create(root=root, target="http://127.0.0.1:8188")

# print the public URL
print(f"Access proxy at: {proxy.endpoints}")
proxy.run()

```

---

<div class="post-metadata">

**Author:** ![krigeta](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/krigeta/32/3097_2.png) [@krigeta](https://openziti.discourse.group/u/krigeta)\
**Post date:** [February 11, 2025, 5:57am UTC](https://openziti.discourse.group/t/can-i-achieve-something-similar-using-zrok-instead-of-ngrok-possible/3837/10 "2025-02-11T05:57:20Z")

</div>

The odd thing is when I install zrok using this command:  
pip install zrok==0.4.47

then when I try to run this command:  
zrok config set apiEndpoint [https://api.zrok.io](https://api.zrok.io)

I got this error:  
/bin/bash: line 1: Zrok: command not found

do I have to install the Zrok installation file?

---

<div class="post-metadata">

**Author:** ![krigeta](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/krigeta/32/3097_2.png) [@krigeta](https://openziti.discourse.group/u/krigeta)\
**Post date:** [February 11, 2025, 6:08am UTC](https://openziti.discourse.group/t/can-i-achieve-something-similar-using-zrok-instead-of-ngrok-possible/3837/11 "2025-02-11T06:08:33Z")

</div>

so the problem was I need to install the zrok\_0.4.47\_linux\_amd64.tar.gz and now the things are working as it supposed too, thank you so much

---

<div class="post-metadata">

**Author:** ![qrkourier](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/qrkourier/32/52_2.png) [@qrkourier](https://openziti.discourse.group/u/qrkourier)\
**Post date:** [February 11, 2025, 10:31pm UTC](https://openziti.discourse.group/t/can-i-achieve-something-similar-using-zrok-instead-of-ngrok-possible/3837/12 "2025-02-11T22:31:20Z")

</div>

You needed to install the `zrok` executable so you could `zrok enable`, correct?

> **[Install | Zrok](https://docs.zrok.io/docs/guides/install/)**
>
> \<DownloadCard

---

<div class="post-metadata">

**Author:** ![krigeta](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/krigeta/32/3097_2.png) [@krigeta](https://openziti.discourse.group/u/krigeta)\
**Post date:** [February 13, 2025, 4:08pm UTC](https://openziti.discourse.group/t/can-i-achieve-something-similar-using-zrok-instead-of-ngrok-possible/3837/13 "2025-02-13T16:08:55Z")

</div>

yes, I did zrok enable token and I got the shared URL but it is not loading, keep scrolling, its been 2 days but no solution. I am sharing all the zrok code I am using on kaggle notebook:

```auto
!pip install zrok==0.4.47
!pip install waitress
!mkdir -p /kaggle/working/zrok
%cd /kaggle/working/zrok
!wget https://github.com/openziti/zrok/releases/download/v0.4.47/zrok_0.4.47_linux_amd64.tar.gz
!tar -xvf ./zrok*.gz  
!chmod a+x /kaggle/working/zrok/zrok

#set the endpoint to work
!/kaggle/working/zrok/zrok config set apiEndpoint https://api.zrok.io

# Enable zrok with your token
token = "my_secret_token"
!/kaggle/working/zrok/zrok enable $token

from zrok.proxy import ProxyShare
import zrok

# Load the environment
root = zrok.environment.root.Load()

# Create a temporary proxy share (will be cleaned up on exit)
proxy = ProxyShare.create(root=root, target="http://127.0.0.1:8188")

# print the public URL
print(f"Access proxy at: {proxy.endpoints}")
proxy.run()

```

it is giving me share URL but nothing is loading and no error so far. but if I use:  
`!kaggle/working/zrok/zrok share public [http://localhost](http://localhost/):{port} --headless`

then I got the URL and it works but not the one you suggested. please help.

---

<div class="post-metadata">

**Author:** ![qrkourier](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/qrkourier/32/52_2.png) [@qrkourier](https://openziti.discourse.group/u/qrkourier)\
**Post date:** [February 13, 2025, 10:04pm UTC](https://openziti.discourse.group/t/can-i-achieve-something-similar-using-zrok-instead-of-ngrok-possible/3837/14 "2025-02-13T22:04:06Z")

</div>

I signed up for Kaggle to see how it works. Is your goal to proxy to a local webserver like `http://127.0.0.1:8188` that is provided by a previous cell in the same notebook, a different notebook, or some other background service?

I'm very new at Kaggle, and I had trouble running the first commands in your example, e.g. `pip install waitress`. I tried the default simple index and pypi index but I keep getting a timeout. It's as if my Kaggle instance can't reach the internet to install from PyPi. _After some forum diving, I suspect internet-enabled kernels are disabled for brand-new Kaggle users._

Another option, if the webserver you're sharing with zrok happens to be a Python application in the same notebook, you can bypass the proxy entirely by modifying your Python webserver to use the zrok SDK directly, like this: [The Python zrok SDK](https://blog.openziti.io/the-python-zrok-sdk) and [zrok/sdk/python/examples/http-server at main · openziti/zrok · GitHub](https://github.com/openziti/zrok/tree/main/sdk/python/examples/http-server)

EDIT: I finally found a "session options" toggle for the internet access in the sidebar. It's disabled with tooltip: "Your account must be phone verified to access the internet."

---

<div class="post-metadata">

**Author:** ![qrkourier](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/qrkourier/32/52_2.png) [@qrkourier](https://openziti.discourse.group/u/qrkourier)\
**Post date:** [February 17, 2025, 5:24pm UTC](https://openziti.discourse.group/t/can-i-achieve-something-similar-using-zrok-instead-of-ngrok-possible/3837/15 "2025-02-17T17:24:47Z")

</div>

After I learned how to enable internet access for my Kaggle kernel, I was able to use zrok's ProxyShare by following your example and making some modifications while I was troubleshooting and learning to use Kaggle.

Here's the public share link for my Kaggle notebook with example output: [zrok-proxy-share | Kaggle](https://www.kaggle.com/code/kennethbingham/zrok-proxy-share)

Still, the state of the Kaggle notebook was not clear to me at all times, and I found it helpful to run the cells individually in sequence.
