Zrok Self Host with dynamic ip and cloudns

Hello everyone. I have a domain registered with CloudNS and would like to know if I can host Zrok on a server on my local network with an ISP that provides me with a dynamic IP. Could someone tell me how I can access services on my local network with Zrok from the CloudNS domain? I tried following the guides, but I'm new to this and can't connect. Thanks.

Hey there, @zebbit :waving_hand:

Sure, you can self-host your zrok instance with dynamic DNS as long as CloudNS supports wildcard DNS.

zrok requires a wildcard DNS record because each public share is built from a template like https://{token}.{zone}. The token is not predictable and zrok doesn't create any DNS records, so you need a wildcard record like *.{zone} in advance that resolves to your dynamic public IP address in CloudNS.

You will also need a wildcard TLS certificate for the zrok frontend for the same reason. You could accomplish this with Caddy, Nginx Cert Manager, or Certbot. I'm most familiar with and prefer Caddy. Here's the self-hosting guide for Docker which includes Caddy for managing your wildcard certificate: Self-hosting guide for Docker | zrok

You will need to open at least three TCP ports in your firewall (default: 80, 443, 3022).

Hey qrkourier, I really appreciate your response. It's possible to modify ports 80 and 443, because my internet provider won't let me open those ports, but it does allow me to open others.

You can set any TCP ports you wish, but the steps depend on how you're hosting zrok: Docker, Linux, Kubernetes, etc.

For example, in that Docker guide I linked, Caddy is hard-coded to 443/TCP.

If you're using Docker, the other ports can be set in your Docker Compose .env file in the same directory as the compose.yml file.

ZITI_CTRL_ADVERTISED_PORT=1280
ZITI_ROUTER_PORT=3022

To test your idea of using a custom port, I made a version of the zrok Docker instance script that allows you to override port 443 like this.

CADDY_HTTPS_PORT=1443
ZITI_CTRL_ADVERTISED_PORT=1280
ZITI_ROUTER_PORT=3022

To try this experimental version, you can follow the same Docker guide I linked above, only use this command to download the Docker instance files to your Compose project directory.

curl -sSf https://get.openziti.io/zrok-instance/fetch.bash | ZROK_REPO_ZIP=https://github.com/openziti/zrok/archive/refs/heads/docker-instance-set-caddy-port.zip bash

Perfect, I'll try it now. I'll tell you later how it went. Really thanks for all, I work for a public school and the school can no longer afford hosting, so I thought Zrok could be a perfect fit to be able to display the school's website and allow students to access it.

2 Likes

That's a good use of zrok!

After you get the self-hosted zrok instance up and running, your next step will be to explore zrok shares. Since you're interested in web hosting with zrok, I assume you'll use zrok public shares to publish an existing web server with zrok's default mode proxy, or you may have some static HTML files you wish to publish with zrok's backend mode web.

For whichever backend mode you choose, we've organized some of our zrok docs around the idea of a reliable web hosting scenario and call that the "zrok frontdoor." We have examples for Docker and Linux here for an always-on zrok service that starts automatically with each reboot: zrok frontdoor | zrok

I'm already trying ZROK, but without self-hosting in proxy mode, and it's working very well (great work, Ken!), so I decided to self-host it on some old servers the school had, where I was able to get Proxmox working.
On an LXD with Ubuntu, I installed Docker with Portainer, and that's where I'm trying to get it working. But I'm having trouble accessing port 18080 over the network. It's refusing the connection. So I think I'm having some problem with the container's port mapping.

I can see why you might want to have a published port to your Docker container as a side door to the server even if you're also publishing the server port with zrok.

I understand your Docker container where the server is running is listening some port inside the Docker bridge network, and you're trying to publish it on 18080/TCP.

Is that accurate?

I assume Portainer is a web UI for managing Docker containers. Does it allow you to specify container configurations with the standard Docker Compose, or are you configuring things in a web UI or something else?

In Docker terminology, the container's application port where it "listens" for connections is usually declared in the container image's Dockerfile with the EXPOSE directive, or in its compose.yml file in the list of ports to expose. "Expose" means the server listens on that port inside the Docker bridge network. Docker also has the term "publish," meaning forwarding some port on the Docker host to the container's exposed port, making that forwarded port available outside the isolated Docker bridge network.

In your case, the Docker host is the LXD container running on Proxmox, so you have an additional network layer to configure to allow publishing. That's where I'd look first for issues, to ensure you can reach a port on the Docker host (the LXD container) from your computer you're using for administrative access.

You could run tcpdump -i eth0 tcp port 1234, substituting the Docker host's interface device name, to sniff for incoming connections on some TCP port.

Good luck!

Yes, Portainer (portainer.io) is a web UI for managing Docker containers

When i run curl -v http://0.0.0.0:18080 from the computer (localhost), i can access to the zrok login page, but when i try from another computer over the network, the connection is refused

Now I understand you're trying to reach the controller API and web console port published to the Docker host (default: 127.0.0.1).

See this part of the Docker self-hosting guide:

#
## if not using Caddy for TLS, uncomment to publish the insecure ports to the internet
#
#ZROK_INSECURE_INTERFACE=0.0.0.0

If using the Docker Compose example from the guide, setting this variable to 0.0.0.0 will cause the insecure API and console port to be reachable on the Docker host's interfaces, not only its loopback interface.

OHHHHHHH ok ok i got it! let me try.
in this part:

plugin name for your DNS provider

CADDY_DNS_PLUGIN=cloudflare

API token from your DNS provider

CADDY_DNS_PLUGIN_TOKEN=abcd1234

use the staging API until you're sure everything is working to avoid hitting the rate limit

CADDY_ACME_API=https://acme-staging-v02.api.letsencrypt.org/directory

for cloudNS i have to do something or just only comment that lines?

You're asking how to get a wildcard certificate when your DNS is provided by CloudNS.

Short answer:

The steps are the same as when DNS provider is Route53 because CloudNS and Route53 both have multiple login values, whereas CloudFlare uses a single token. Look in the zrok Docker guide in the troubleshooting section for "My DNS provider credential is composed of several values, not a single API token."


Detailed answer:

Here's the CloudNS instructions for their Caddy plugin: GitHub - caddy-dns/cloudns

After following the zrok instructions, you must change the Caddyfile you downloaded for the zrok Docker guide to resemble their instructions, e.g., like this to configure the plugin with inherited env vars:

tls {
  dns cloudns
}

In your zrok compose project's .env, assign the DNS-related variables. You'll get values starting with CLOUDNS_ from CloudNS.

CADDY_DNS_PLUGIN=cloudns
CLOUDNS_AUTH_ID=***
CLOUDNS_SUB_AUTH_ID=***
CLOUDNS_AUTH_PASSWORD=***

You must also declare these new env vars in the compose.override.yml file you renamed from compose.caddy.yml like this. You don't need to assign a value in the compose file because it's assigned in the .env and will pass through.

services:
  caddy:
    environment:
      CLOUDNS_AUTH_ID:
      CLOUDNS_SUB_AUTH_ID:
      CLOUDNS_AUTH_PASSWORD:
1 Like

Perfect, i think i'm getting it.
Do you think is better install zrok under linux or with docker in my case?

I recommend the Docker path because it is fairly complete with the scripted and documented support for Caddy or Traefik for TLS.

You can do all the same things directly on Linux, but the Docker Compose example does almost everything for you.

You are the best ken! Sorry for all the questions (some may be silly). I'm trying to get this working for school (I thought I'd give you credit and advertise the fact that the page works with Zrok, if you don't mind).
I have a few questions: Can I point the wildcard required by Zrok to NOIP in my CloudNS DNS zone? Because we don't have a fixed IP on our router. Could Zrok resolve incoming domains by having to go through NOIP? For example, if the domain is support.xxx.xxx, it will take me to the support page, and if I put notices.xxx.xxx, it will take me to the news page?

You're welcome.

You're using a dynamic public IP with a DNS provider, CloudNS, that updates your DNS record when your public IP changes.

For zrok, your DNS provider must support wildcard records. When you follow the Docker or Linux or Kubernetes self-hosting guides, you'll be advised to create a wildcard DNS record for your chosen DNS zone (e.g., a subdomain for zrok). If your chosen DNS zone for zrok is zrok.example.com, then you must create a wildcard DNS record *.zrok.example.com resolving to the public IP where zrok's ports are published.

Yes, you can reserve unique public share names like "support" and "notices" and, as long as the zrok share backend is running, any visitors to those names will arrive at the appropriate site, e.g., support.zrok.example.com.

Can you believe I just realized CloudNs has dynamic DNS? Thanks a lot!

Does CloudNS also support wildcard records with dynamic DNS?

Yes, free account have 1 ddns, so I used it for the wildcard.

1 Like

Good to know! Thank you.