sinamics / ztnet

ZTNET - ZeroTier Web UI for Private Controllers with Multiuser and Organization Support.
https://ztnet.network
GNU General Public License v3.0
481 stars 45 forks source link

[Support]: Connecting to service on self-hosted controller on its own network #249

Closed BrianVB closed 8 months ago

BrianVB commented 8 months ago

📝 Describe the Problem You Are Having

I am unable to connect to services that are being hosted on the same machine that ztnet and Zerotier are. My test is with a instance of Vaultwarden I have running on the server. Both Vaultwarden, and ztnet are running in Docker containers on the server, set up through Portainer.

When on the local network, I can connect to Vaultwarden using the IP address of the machine assigned by the router (192.168.1.132) but cannot access it via the IP assigned by Zerotier. I can ping both IPs without any issue.

bvb@bvb-desktop:/media/bvb/Ubuntu-bak/sd$ ping 192.168.1.132
PING 192.168.1.132 (192.168.1.132) 56(84) bytes of data.
64 bytes from 192.168.1.132: icmp_seq=1 ttl=64 time=3.18 ms
64 bytes from 192.168.1.132: icmp_seq=2 ttl=64 time=3.14 ms
64 bytes from 192.168.1.132: icmp_seq=3 ttl=64 time=3.12 ms
^C
--- 192.168.1.132 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 3.115/3.145/3.180/0.026 ms

bvb@bvb-desktop:/media/bvb/Ubuntu-bak/sd$ ping 10.121.15.127
PING 10.121.15.127 (10.121.15.127) 56(84) bytes of data.
64 bytes from 10.121.15.127: icmp_seq=1 ttl=64 time=12.4 ms
64 bytes from 10.121.15.127: icmp_seq=2 ttl=64 time=5.06 ms
64 bytes from 10.121.15.127: icmp_seq=3 ttl=64 time=6.12 ms
^C
--- 10.121.15.127 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 5.057/7.870/12.437/3.257 ms

bvb@bvb-desktop:/media/bvb/Ubuntu-bak/sd$ curl 192.168.1.132:5555
<!doctype html><html class="theme_light"><head><meta charset="utf-8"/><meta name="viewport" content="width=1010"/><meta name="theme-color" content="#175DDC"/><title page-title>Vaultwarden Web</title><link rel="apple-touch-icon" sizes="180x180" href="images/apple-touch-icon.png"/><link rel="icon" type="image/png" sizes="32x32" href="images/favicon-32x32.png"/><link rel="icon" type="image/png" sizes="16x16" href="images/favicon-16x16.png"/><link rel="mask-icon" href="images/safari-pinned-tab.svg" color="#175DDC"/><link rel="manifest" href="cca56971e438d22818d6.json"/><script defer="defer" src="theme_head.1df11f603fda400762b7.js"></script><link href="app/main.a5d3a3a9125fcf07f286.css" rel="stylesheet"></head><body class="layout_frontend"><app-root><div class="mt-5 d-flex justify-content-center"><div><img class="mb-4 logo logo-themed" alt="Vaultwarden logo"/><p class="text-center"><i class="bwi bwi-spinner bwi-spin bwi-2x text-muted" title="Loading" aria-hidden="true"></i></p></div></div></app-root><script defer="defer" src="app/polyfills.4275a7f2798b637a6613.js"></script><script defer="defer" src="app/vendor.351bf938ddfd5e202e99.js"></script><script defer="defer" src="app/main.b193f247301cc37bf60b.js"></script></body></html>

bvb@bvb-desktop:/media/bvb/Ubuntu-bak/sd$ curl 10.121.15.127:5555
curl: (7) Failed to connect to 10.121.15.127 port 5555 after 6 ms: Connection refused
bvb@bvb-desktop:/media/bvb/Ubuntu-bak/sd$ 

I was helped in this issue ( https://github.com/sinamics/ztnet/issues/119#issuecomment-1863703877 ) getting the Zerotier node to join the controller on its own machine and it's apparent that there may be some networking things that I do not understand about this setup.

I currently run Zerotier a different local machine using ztncui in this fashion. A self-hosted Zerotier controller is on the machine with ztncui; the node joined its own network; and I have services running on the machine which I am able to access without issue.

Something about the ztnet setup preventing me from connecting to these services using the IP address assigned by Zerotier. Is this something that I can make possible using the configuration provided by ztnet?

🔖 Version

Latest ( ID sha256:6a7ec8eb9744993a8ddf776014afbe2dabb53b82719a3b1a40406167f1788037 )

📋 Docker Logs

Applying migrations to the database...
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource "db": PostgreSQL database "ztnet", schema "public" at "postgres:5432"

22 migrations found in prisma/migrations

No pending migrations to apply.
Migrations applied successfully!
Seeding the database...
Environment variables loaded from .env
Running seed command `ts-node --compiler-options {"module":"CommonJS"} prisma/seed.ts` ...
Seeding:: User Options complete!
Seeding:: Updating user ID complete!

🌱  The seed command has been executed.
Database seeded successfully!
Executing command
   ▲ Next.js 14.0.3
   - Local:        http://fad6511f2d39:3000
   - Network:      http://172.31.255.4:3000

 ✓ Ready in 85ms
Socket is initializing

💻 Operating System

Ubuntu

📚 Any Other Information That May Be Helpful

No response

sinamics commented 8 months ago

With the default configuration, each container is connected to a Docker bridge network 172.31.255.0/29. When you connect the Zerotier container to its own Zerotier network, it becomes isolated from other services running on the local machine. This isolation occurs because, by default, there is no routing set up to handle traffic between the Zerotier network and the Docker bridge network or the local network.

Docker containers are isolated from the local network unless you specifically configure them to use the host network. This isolation is part of Docker's design to ensure that containerized applications run in a predictable and secure environment.

You have two options:

  1. Modify the configuration of the Zerotier container to utilize the host's network directly. By doing this, the container can create zt# interfaces on the host system, mimicking the behavior of a native ZeroTier One installation. This change effectively integrates the Zerotier container with the host's network

  2. Implement Network Routing and Bridging: Instead of using the host network for the Zerotier container, you can set up manual routes or network bridging to allow traffic between the Zerotier network and the Docker internal network. This involves more complex network configuration but maintains better isolation between your Docker containers and the host system.

Solution 1 Example: Change your docker-compose something like this:

Pay attetion to these lines: network_mode: "host" in zerotier section ZT_ADDR: http://10.0.0.214:9993 set the local machine ip address instead of zerotier. Ztnet will connect to zerotier using you local network instead.

Also comment out the port and networks in zerotier.

version: "3.1"
services:
  postgres:
    image: postgres:15.2-alpine
    container_name: postgres
    restart: unless-stopped
    ports:
      - 5432:5432
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: ztnet
    volumes:
      - postgres-data:/var/lib/postgresql/data
    networks:
      - app-network

  zerotier:
    image: zyclonite/zerotier:1.12.2
    hostname: zerotier
    container_name: zerotier
    restart: unless-stopped
    volumes:
      - zerotier:/var/lib/zerotier-one
    cap_add:
      - NET_ADMIN
      - SYS_ADMIN
    devices:
      - /dev/net/tun:/dev/net/tun
    network_mode: "host"
    # networks:
    #   - app-network
    # ports:
    #   - "9993:9993/udp"
    environment:
      - ZT_OVERRIDE_LOCAL_CONF=true

  ztnet:
    image: sinamics/ztnet:latest
    container_name: ztnet
    working_dir: /app
    volumes:
      - zerotier:/var/lib/zerotier-one
      - /etc/localtime:/etc/localtime:ro
    restart: unless-stopped
    ports:
      - 3000:3000
    environment:
      ZT_ADDR: http://10.0.0.214:9993
      POSTGRES_HOST: postgres
      POSTGRES_PORT: 5432
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: postgres
      NEXTAUTH_URL: "https://my_awesome_ztnet.com"
      NEXTAUTH_SECRET: "random_secret"
    networks:
      - app-network
    links:
      - postgres
    depends_on:
      - postgres
      - zerotier
volumes:
  zerotier:
  postgres-data:

networks:
  app-network:
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 172.31.255.0/29

If you type ip a , you will now see the zerotier adapter. You should be able to access services like bitwarden on the local machine using zerotier ip address.

BrianVB commented 8 months ago

Ahhh wow very helpful explanation! Reading your response and seeing the config file with networks commented out pulls it together for me. I am still learning the ins and outs of networking with Docker so this is very new to me and I appreciate your patience explaining it to me.

I'm going to change my tune now, though. Rather than "getting it to work" the same way my current setup is, I'd much rather fully use it as you intended. I enjoy the ztnet UI and options I have to implement things like flow rules, tags, and other settings outside of using the command line. I love what you're doing here and want to keep with that vision. So, if you would be so kind as to share with me how you'd implement a solution for my situation, I'd appreciate it (I'll try to keep it short).

I am volunteering to do dev / IT work for a spiritual/religious organization. I set them up with a NAS (synology) that is self-hosting a zerotier controller as well as Vaultwarden. We want to host more services, and the NAS hardware isn't really enough, so I got them a second server running Ubuntu 22.04.3 which will be the new host for the controller and all other web-based services (the NAS will only be for storage).

So, there are two servers, the Synology NAS, and the Ubuntu box running zerotier and all other services. What would be your preferred way to set this up using ztnet? The most simple solution that comes to mind is to do a basic installation of zerotier on the Ubuntu box (not in a docker container), in addition to having ztnet in the docker containers. Then to just have it join the controller hosted in the setup of the ztnet containers.

Or, if you have an ideal setup for utilizing ztnet in this situation that's different from what I laid out above, I'd love to hear it.

sinamics commented 8 months ago

Glad to hear you enoying ztnet. 🎉 First of, im not a network expert so everything im saying should be taking with a grain of salt. There are many network gurus arround so they might correct me.

So, there are two servers, the Synology NAS, and the Ubuntu box running zerotier and all other services. What would be your preferred way to set this up using ztnet? The most simple solution that comes to mind is to do a basic installation of zerotier on the Ubuntu box (not in a docker container), in addition to having ztnet in the docker containers. Then to just have it join the controller hosted in the setup of the ztnet containers.

It's important to note that you cannot install Zerotier on the host and run ztnet in Docker simultaneously without conflicts, as they both use port 9993 on the host

  1. Just use the example 1 above. This is more or less the same as using the ztnet standalone version. You'll retain all functionalities of ztne

  2. Alternatively, you could install the ztnet standalone version and configure Zerotier to connect to itself.

  3. Install ztnet on an external server and connect both the NAS and the Ubuntu servers to this centralized ztnet server. This method centralizes your network management.

  4. This would be my preferred choice. Install a virtualization engine like Proxmox on the Ubuntu server. Then, spin up a virtual machine (VM) or container specifically for hosting ztnet, and another for Portainer. Each VM will have its own IP address from your router, providing more granular control over your network.

    • Within this setup, you could:
      • Install Zerotier in each VM and NAS and connect them to the ztnet server (VM).
      • Implement routing through the ztnet server, allowing you to access the local network in the same way as if you were on-site.
      • Enhance firewall capabilities using tools like iptables. This setup allows for more sophisticated firewall configurations, enabling better control over network traffic and security.

There is probably a ton of other ways, but these are "top of my head"