📝
Суть этой заметки аналогична этой заметки про Pangolin, но с использованием другого инструмента.

Если VPS новый и нету Docker:

apt update && apt upgrade -y
apt install -y curl wget sudo git
curl -fsSL https://get.docker.com -o get-docker.sh && sudo sh ./get-docker.sh
🚧
Если у вас есть firewall разрешите порты 80/tcp и 443/tcp для получения SSL.

Установка скриптом

Это автоматический скрипт установки и настройки домена панели, а так же других доменов (если надо) и SSL для них. Но NGINX конфиг будет полностью настроен только для панели.

git clone https://github.com/nozsh/home-server-vps-ztnet-init ztnet && cd ztnet && bash init/init.sh

Далее в админке создать сеть. Подключиться к сети на домашнем сервере по инструкции. И на VPS выполнить:

NET_ID="XYZ"; docker exec ztnet sh -c "cd /var/lib/zerotier-one && mkdir networks.d && cd networks.d && touch $NET_ID.conf"

Где XYZ – ID сети.

Если добавляли другие домены помимо панели нужно отредактировать NGINX конфиги – изменить proxy_pass. Можно не добавлять доп. домены сразу. Потом просто использовать скрипт. Где <ZeroTier_IP> IP домашнего сервера в ZeroTier сети, APP_PORT порт на котором работает сервис на домашнем сервере.

docker compose down && docker compose up -d && docker compose logs -f

И если с домашним сервером потерялся коннект:

sudo systemctl restart zerotier-one

Вручную

mkdir ztnet && cd ztnet && wget -O docker-compose.yml https://raw.githubusercontent.com/sinamics/ztnet/main/docker-compose.yml
nano docker-compose.yml

Меняйте все как вам нужно согласно документации.

Reverse proxy (NGINX)

nano docker-compose.yml

Должно быть вот так:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
services:
  zerotier:
    ports:
      - "9993:9993/udp"
      - "80:80"
      - "443:443"

  nginx:
    image: nginx:alpine
    container_name: nginx
    restart: unless-stopped
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
      - /etc/letsencrypt:/etc/letsencrypt:ro
    network_mode: "service:zerotier"
    depends_on:
      - zerotier
Пример полного docker-compose.yml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
services:
  postgres:
    image: postgres:15.2-alpine
    container_name: postgres
    restart: unless-stopped
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: database_password
      POSTGRES_DB: ztnet
    volumes:
      - postgres-data:/var/lib/postgresql/data
    networks:
      - app-network

  zerotier:
    image: zyclonite/zerotier:1.14.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
    networks:
      - app-network
    ports:
      - "9993:9993/udp"
      - "80:80"
      - "443:443"
    environment:
      - ZT_OVERRIDE_LOCAL_CONF=true
      - ZT_ALLOW_MANAGEMENT_FROM=172.31.255.0/29

  ztnet:
    image: sinamics/ztnet:latest
    container_name: ztnet
    working_dir: /app
    volumes:
      - zerotier:/var/lib/zerotier-one
    restart: unless-stopped
    ports:
      - 3000:3000
    environment:
      POSTGRES_HOST: postgres
      POSTGRES_PORT: 5432
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: database_password
      POSTGRES_DB: ztnet
      NEXTAUTH_URL: "https://ztnet-panel.domain.org"
      NEXTAUTH_SECRET: "something_random"
      NEXTAUTH_URL_INTERNAL: "http://ztnet:3000"
    networks:
      - app-network
    links:
      - postgres
    depends_on:
      - postgres
      - zerotier

  nginx:
    image: nginx:alpine
    container_name: nginx
    restart: unless-stopped
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
      - /etc/letsencrypt:/etc/letsencrypt:ro
    network_mode: "service:zerotier"
    depends_on:
      - zerotier
 
volumes:
  zerotier:
  postgres-data:
 
networks:
  app-network:
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 172.31.255.0/29

NGINX конфиги

mkdir -p nginx/conf.d
nano nginx/conf.d/panel-ztnet.domain.org.conf
Конфиг для панели
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
server {
    listen 80;
    server_name ztnet-panel.domain.org;

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl;
    server_name ztnet-panel.domain.org;

    ssl_certificate /etc/letsencrypt/live/ztnet-panel.domain.org/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/ztnet-panel.domain.org/privkey.pem;

    ssl_session_cache shared:le_nginx_SSL:10m;
    ssl_session_timeout 1440m;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;

    location / {
        proxy_pass http://ztnet:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
nano nginx/conf.d/your-app.domain.org.conf
Конфиг для каких-то сервисов
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
server {
    listen 80;
    server_name your-app.domain.org;

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl;
    server_name your-app.domain.org;

    ssl_certificate /etc/letsencrypt/live/your-app.domain.org/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your-app.domain.org/privkey.pem;

    ssl_session_cache shared:le_nginx_SSL:10m;
    ssl_session_timeout 1440m;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;

    location / {
        proxy_pass http://<ZeroTier_IP>:APP_PORT;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Поменять там где выделено. Где <ZeroTier_IP> IP домашнего сервера в ZeroTier сети, APP_PORT порт на котором работает сервис на домашнем сервере.

SSL

SSL можно получить через тот же Docker, но проще будет через хост.

apt install certbot
certbot certonly --standalone --non-interactive --agree-tos --email [email protected] -d ztnet-panel.domain.org
ls /etc/letsencrypt/live/
💡
SSL не получится получить/обновить, если запущен контейнер zerotier, из-за конфликта портов.

Запуск

docker compose up -d && docker compose logs -f

В админке создать сеть. Подключиться к сети на домашнем сервере по инструкции. Далее нужно добавить VPS на котором работает ZTNet в сеть с домашнем сервером:

docker exec -it ztnet sh
cd /var/lib/zerotier-one
mkdir networks.d
cd networks.d
touch <network>.conf

Где <network> – ID сети.

exit
docker compose down && docker compose up -d && docker compose logs -f

И если с домашним сервером потерялся коннект:

sudo systemctl restart zerotier-one

Добавление/Настройка сервисов (NGINX)

Чтобы добавить новый сервис, скопируйте существующую конфигурацию NGINX, и поменяйте домен и proxy_pass. И запросите SSL сертификат.

docker compose down && docker compose up -d && docker compose logs -f

Или если вы использовали скрипт автоматической настройки, из директории где docker-compose.yml выполнить:

bash init/add_new.sh

Скрипт остановит контейнеры, создаст NGINX конфиг, запросит SSL и запустит контейнеры. Если ошибок не было – руками ничего делать не требуется.

Полезные команды

Docker

Проверить что соединение доходит до вашего домашнего сервера через контейнер NGINX, можно командой:

docker exec nginx wget -O- http://<ZeroTier_IP>:APP_PORT --timeout=5

Если что-то не запустилось, и/или работает не правильно после:

docker compose restart && docker compose logs -f

Выполните:

docker compose down && docker compose up -d && docker compose logs -f

ZeroTier

sudo zerotier-cli join <network>
sudo zerotier-cli leave <network>
sudo zerotier-cli listnetworks

Скрипты

VPS

“certbot_renew.sh”:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#!/bin/bash

cd /root/ztnet
docker compose down

certbot renew --quiet
#certbot renew

bash start_nologs.sh
#bash restart_nologs.sh

Там же где docker-compose.yml:

“start.sh”:

1
2
3
#!/bin/bash

docker compose up -d && docker compose logs -f

“start_nologs.sh”:

1
2
3
#!/bin/bash

docker compose up -d

“restart.sh”:

1
2
3
4
#!/bin/bash

docker compose down
docker compose up -d && docker compose logs -f

“restart_nologs.sh”:

1
2
3
4
#!/bin/bash

docker compose down
docker compose up -d

Cron

sudo crontab -e

VPS:

0 4 1 * * /bin/bash /root/certbot_renew.sh

Домашний сервер:

2 4 1 * * systemctl restart zerotier-one