# SKNet

Выберите сценарий. В каждой инструкции есть объяснение человеческим языком, готовая конфигурация и способ проверить результат.

Полный текст базы одним файлом. Отдельные документы и их исходники — http://docs.sknet.gitaspen.ru/llms.txt

---

Документ: http://docs.sknet.gitaspen.ru/01-start/quickstart

# Первый туннель за несколько минут

Создаём публичный HTTPS-адрес для сервиса, который уже запускается через Docker.

## Что получится

Предположим, ваш сайт открывается внутри Docker по адресу http://app:80. После настройки он будет доступен по адресу https://my-app.sknet.gitaspen.ru.

На компьютере не нужно открывать порт 80 или 443. Контейнер SKNet сам устанавливает исходящее защищённое соединение.

> **Обратите внимание.** Имя my-app — пример. Служебные и официально выглядящие имена SKNet не выдаёт.

## 1. Создайте туннель

1. **Откройте кабинет.** Войдите через единый аккаунт GitAspen и нажмите «Новый туннель».
2. **Задайте имя.** Короткое имя становится частью адреса: my-app → my-app.sknet.gitaspen.ru.
3. **Выпустите токен.** Секрет показывается один раз. Скопируйте его в .env или менеджер секретов.

## 2. Добавьте контейнер

Добавьте сервис tunnel рядом с приложением. В SKNET_LOCAL указывается внутренний Docker-адрес приложения, а не localhost вашего браузера.

**compose.yml**

```
services:
  app:
    image: nginx:alpine

  tunnel:
    image: sknet/sknet:latest
    command: [client]
    restart: unless-stopped
    environment:
      SKNET_REMOTE: control.sknet.gitaspen.ru:7000
      SKNET_TOKEN: ${SKNET_TOKEN:?Добавьте токен в .env}
      SKNET_TLS: "1"
      SKNET_NAME: my-app
      SKNET_LOCAL: http://app:80
    depends_on:
      - app
```

## 3. Сохраните токен

**.env**

```
SKNET_TOKEN=snet_ваш_секретный_токен
```

> **Осторожно.** Файл .env не добавляют в Git. В репозитории оставляют только .env.example без значения.

## 4. Запустите

**Терминал**

```
docker compose up -d

docker compose logs -f tunnel
```

> **Готово.** Когда в логе появится secure tunnel established, откройте публичный адрес из кабинета.

## Если приложение не в Docker

Контейнер должен уметь обратиться к приложению на хосте. На Windows и macOS обычно подходит host.docker.internal.

**compose.yml**

```
environment:
  SKNET_LOCAL: http://host.docker.internal:3000
```

---

Документ: http://docs.sknet.gitaspen.ru/02-basics/how-it-works

# Как SKNet работает на самом деле

Простое объяснение без сетевой теории: кто к кому подключается и где проходят данные.

## Короткая версия

SKNet состоит из публичного edge-сервера и маленького клиента рядом с вашим приложением.

Клиент первым подключается к edge-серверу. Поэтому домашний роутер, NAT и закрытые входящие порты не мешают работе. Когда человек открывает публичный адрес, edge передаёт запрос через уже созданное соединение.

## Путь одного запроса

1. **DNS находит SKNet.** Браузер узнаёт IP публичного edge-сервера.
2. **Edge принимает HTTPS.** SKNet завершает TLS и по имени домена находит нужный активный туннель.
3. **Запрос идёт в ваш клиент.** Для каждого потока открывается отдельное соединение, поэтому большой ответ не блокирует остальные.
4. **Клиент обращается к приложению.** Например, к http://app:3000 внутри вашей Docker-сети.
5. **Ответ возвращается тем же путём.** Браузер получает обычный HTTPS-ответ и не знает, где физически запущено приложение.

## Что видит SKNet

| SKNet видит | SKNet не получает автоматически |
|---|---|
| HTTP-запросы, проходящие через туннель | Доступ ко всем файлам компьютера |
| Публичное имя туннеля и состояние соединения | Доступ к другим контейнерам |
| Технические сведения для маршрутизации | Пароли приложения и баз данных |

## Что происходит при остановке

Публичный адрес остаётся закреплён за аккаунтом, но отвечает, что туннель сейчас недоступен. После повторного запуска клиент подключается снова с тем же токеном — DNS менять не нужно.

---

Документ: http://docs.sknet.gitaspen.ru/03-connect/docker

# Docker Compose: готовые сценарии

Примеры для приложения в Compose, приложения на хосте и нескольких сервисов.

## Приложение в том же Compose

Используйте имя сервиса и его внутренний порт. Публиковать порт приложения на хост необязательно.

**compose.yml**

```
services:
  app:
    image: nginx:alpine

  tunnel:
    image: sknet/sknet:latest
    command: [client]
    restart: unless-stopped
    environment:
      SKNET_REMOTE: control.sknet.gitaspen.ru:7000
      SKNET_TOKEN: ${SKNET_TOKEN:?Добавьте токен в .env}
      SKNET_TLS: "1"
      SKNET_NAME: my-app
      SKNET_LOCAL: http://app:80
    depends_on:
      - app
```

## Приложение запущено на компьютере

**compose.yml**

```
services:
  tunnel:
    image: sknet/sknet:latest
    command: [client]
    environment:
      SKNET_REMOTE: control.sknet.gitaspen.ru:7000
      SKNET_TOKEN: ${SKNET_TOKEN}
      SKNET_TLS: "1"
      SKNET_NAME: local-api
      SKNET_LOCAL: http://host.docker.internal:8000
```

## Несколько приложений

Для каждого публичного проекта создайте отдельный туннель и отдельный токен. Так один отозванный токен не затронет остальные проекты.

**compose.yml**

```
services:
  site-tunnel:
    image: sknet/sknet:latest
    command: [client]
    environment:
      SKNET_NAME: site
      SKNET_TOKEN: ${SKNET_SITE_TOKEN}
      SKNET_REMOTE: control.sknet.gitaspen.ru:7000
      SKNET_TLS: "1"
      SKNET_LOCAL: http://site:3000

  api-tunnel:
    image: sknet/sknet:latest
    command: [client]
    environment:
      SKNET_NAME: api
      SKNET_TOKEN: ${SKNET_API_TOKEN}
      SKNET_REMOTE: control.sknet.gitaspen.ru:7000
      SKNET_TLS: "1"
      SKNET_LOCAL: http://api:8000
```

> **Осторожно.** Имя api зарезервировано самим SKNet. В реальном проекте используйте, например, my-api.

## WebSocket и большие ответы

Дополнительная настройка не нужна. Upgrade-запросы и потоковые тела проходят через тот же HTTP-туннель.

---

Документ: http://docs.sknet.gitaspen.ru/04-domains/custom-domain

# Собственный домен

Как подключить dev.example.ru, проверить DNS и получить HTTPS автоматически.

## До начала

Домен должен принадлежать вам, а в панели регистратора должна быть возможность менять DNS-записи. Сам сайт может оставаться где угодно — мы меняем только выбранный поддомен.

## 1. Добавьте домен в кабинет

Откройте нужный туннель, выберите «Свой домен» и укажите полное имя, например dev.example.ru. SKNet покажет точную DNS-запись.

## 2. Создайте CNAME

| Поле | Значение |
|---|---|
| Тип | CNAME |
| Имя / Host | dev |
| Значение / Target | edge.sknet.gitaspen.ru |
| TTL | Авто или 300 секунд |

> **Обратите внимание.** В некоторых панелях нужно вводить только dev, а домен example.ru добавится автоматически.

## 3. Дождитесь DNS

Обновление обычно занимает несколько минут, но иногда провайдеру требуется до суток. Нажмите «Проверить DNS» в кабинете.

**Необязательная проверка в терминале**

```
nslookup -type=CNAME dev.example.ru
```

## 4. HTTPS появится автоматически

После успешной проверки запустите туннель. Edge запросит сертификат только для домена, который закреплён за вашим аккаунтом и активным туннелем.

> **Готово.** Тот же туннель продолжит работать и по адресу SKNet, и по вашему домену.

## Корневой домен без поддомена

Не каждый DNS-провайдер разрешает CNAME для example.ru. Используйте ALIAS/ANAME или CNAME flattening, если они есть. Самый простой и переносимый вариант — поддомен вроде app.example.ru.

---

Документ: http://docs.sknet.gitaspen.ru/05-security/security

# Токены и безопасная работа

Что защищает проекты разных пользователей и как не утечь собственным токеном.

## Один токен — один туннель

Токен закреплён за конкретным аккаунтом и туннелем. С его помощью нельзя занять чужое имя или подключить домен, который не был подтверждён в кабинете.

## Секрет показывается один раз

В базе хранится только хеш. Если значение потеряно, старый токен отзывают и выпускают новый. Подсмотреть старый секрет через кабинет или API нельзя.

**.gitignore**

```
.env
.env.*
!.env.example
```

## Когда отозвать токен

1. **Он попал в Git или лог.** Отзовите сразу, даже если репозиторий приватный.
2. **Участник покинул проект.** Создайте новый токен и замените его в deployment secrets.
3. **Проект больше не используется.** Удалите туннель — связанные токены и домены перестанут работать.

## Не публикуйте внутренние панели без защиты

SKNet делает сервис доступным из интернета, но не добавляет приложению собственную авторизацию. Если у панели нет входа, любой человек со ссылкой сможет её открыть.

> **Осторожно.** Базы данных, Redis, Docker API и административные порты нельзя публиковать как обычный HTTP-туннель.

---

Документ: http://docs.sknet.gitaspen.ru/06-help/troubleshooting

# Если что-то не работает

Проверка по цепочке: контейнер, локальный адрес, токен, DNS и HTTPS.

## Туннель offline

1. **Посмотрите логи.** docker compose logs tunnel покажет ошибку подключения или авторизации.
2. **Проверьте токен.** Убедитесь, что в .env нет кавычек, пробелов и старого отозванного значения.
3. **Проверьте TLS.** SKNET_TLS должен быть равен 1, remote — control.sknet.gitaspen.ru:7000.

## Адрес отвечает 502/504

Edge нашёл туннель, но клиент не смог обратиться к приложению. Обычно ошибочен SKNET_LOCAL или приложение ещё не запущено.

**Проверка из контейнера туннеля**

```
docker compose exec tunnel wget -qO- http://app:3000
```

## Свой домен не подтверждается

Проверьте, что CNAME создан для точного поддомена и указывает на edge.sknet.gitaspen.ru. Удалите конфликтующие A/AAAA-записи для того же имени.

## HTTPS ещё не готов

Сертификат запрашивается после успешной проверки DNS и первого обращения к активному туннелю. Подождите минуту и обновите страницу.
