Connector · Docker
Запустите Connector в контейнере — без входящего порта
Официальный образ ghcr.io/termalinapp/termalin-connector запускает Termalin Connector в одном контейнере на любой машине сети — NAS, домашней лаборатории, роутере, кластере Kubernetes, сервисе ECS. Он идёт наружу к Termalin и достаёт до серверов, внутренних сайтов и рабочих столов в этой сети, не открывая входящего порта. Около 4 МБ, amd64/arm64, работает под uid 10001.
amd64 / arm64 · без входящего порта · Pro (или 14 дней бесплатно)
01 / зачем контейнер
Один контейнер в сети, ничего открывать не нужно
Connector позволяет Termalin достучаться до приватной машины без входящего порта и без долговременного ключа на ней. Какие-то машины проще добавить контейнером, чем ставить на них бинарник и службу, а какие-то умеют запускать только контейнеры. Образ подходит им:
- ▸NAS или домашняя лаборатория. Synology, Unraid или Docker-хост в вашей локальной сети — доступ к собственному SSH этой машины и к любому другому серверу, сайту или рабочему столу в сети.
- ▸Роутер. MikroTik RouterOS 7 умеет запускать контейнеры; один держит Connector для самого роутера и всего, что за ним.
- ▸Kubernetes. Deployment с одной репликой достаёт до сервисов кластера по их внутреннему адресу.
- ▸AWS ECS / VPC. Задача Fargate или EC2 только с исходящим HTTPS — без балансировщика и без входящего правила — достаёт до приватных инстансов, внутренних сайтов и рабочих столов.
02 / образ
Четыре мегабайта, без оболочки, без SSH-сервера
Образ — ghcr.io/termalinapp/termalin-connector:<version> (и :latest), для linux/amd64 и linux/arm64.
- ▸Около 4 МБ. Статический Connector, CA-сертификаты и больше ничего — без оболочки, без пакетного менеджера, без SSH-сервера. Работает под uid 10001 и хранит конфигурацию в томе
/data. - ▸Собирается открыто. В публичном репозитории
termalinapp/termalin, только из подписанных релизных бинарников на termal.in — каждый проверяется по манифесту релиза и его подписи, прежде чем попасть внутрь. - ▸armv7 пока не собирается (32-битный ARM). Пока только amd64 и arm64.
03 / быстрый старт
Подключите контейнер одной командой docker run
Получите токен подключения в веб-кабинете (Хосты → + → Connector), затем:
docker run -d --name termalin --restart unless-stopped \ -v termalin:/data \ -e TERMALIN_TOKEN=<token> \ -e TERMALIN_TARGET=192.168.1.10:22 \ -e TERMALIN_USER=deploy \ ghcr.io/termalinapp/termalin-connector
Переменные:
| Переменная | Назначение |
|---|---|
TERMALIN_TOKEN | Токен подключения; используется только при первом запуске, пока в томе ещё нет конфигурации. |
TERMALIN_TARGET | host:port SSH-сервера, куда идут терминалы, команды и файлы (хост Docker или другая машина). Внутри контейнера 127.0.0.1 — это сам контейнер, в котором SSH-сервера нет. |
TERMALIN_USER | Пользователь для входа на этот SSH-сервер (по умолчанию — тот, что задан в аккаунте). |
TERMALIN_NAME | Имя в веб-кабинете (по умолчанию — hostname контейнера; задайте --hostname или эту переменную). |
TERMALIN_SERVER | По умолчанию https://termal.in. |
Первый запуск: если в /data нет конфигурации, а токен задан, контейнер подключается, печатает строку входа ниже и устанавливает соединение. При следующих запусках он просто соединяется — токен может оставаться в окружении, повторно он не отправляется. Если нет ни конфигурации, ни токена, контейнер сообщает об этом и завершается с кодом 1. docker stop останавливает его сразу. Чтобы подключить заново, удалите том и запустите с новым токеном.
04 / строка входа
Доверие сертификату на целевом сервере
Connector в контейнере никогда не трогает целевой сервер. При подключении он печатает строку, которая разрешает вход краткосрочным сертификатам Termalin для этого аккаунта — и docker exec termalin termalin-agent check печатает её снова:
cert-authority,principals="termalin-<account id>" ssh-ed25519 AAAA… termalin-connector
Добавьте её в ~/.ssh/authorized_keys пользователя входа на целевом сервере (одна строка, права файла 600, ~/.ssh — 700). На сервере, которым вы управляете как root, можно вместо этого добавить TrustedUserCAKeys и AuthorizedPrincipalsFile в его sshd_config — check печатает оба варианта. Без этого терминалы и команды через этот Connector целевой сервер отклоняет; веб-ссылкам и рабочим столам она не нужна. check также сообщает, отвечает ли SSH-сервер цели (sshd=up); статус входа — ca=unknown, потому что файлы целевого сервера изнутри контейнера прочитать нельзя.
05 / SSH-сервер не нужен
Внутренние сайты и рабочие столы — без sshd где бы то ни было
Внутренние сайты и удалённые рабочие столы (RDP, VNC) не идут через SSH: бэкенд просит Connector открыть соединение к собственному host:port сайта или рабочего стола, и Connector соединяется туда напрямую. Поэтому контейнер в VPC, сервис ECS или домашняя сеть могут публиковать внутренние сайты и рабочие столы вообще без SSH-сервера. Страница баз данных с паролем базы работает так же — к порту базы данных.
- ▸Только частные адреса. Цели подключения должны быть в частной сети — RFC 1918, loopback, link-local, CGNAT
100.64/10(например, Tailscale), IPv6 ULA. Connector — не ретранслятор в интернет, а облачные адреса метаданных (169.254.169.254и подобные) всегда отклоняются. - ▸Требуют SSH-сервера на целевом сервере: терминал,
ssh_execи остальные инструменты команд, файлы по SFTP, беспарольные инструменты баз данных, метрики и бэкапы. ЗадайтеTERMALIN_TARGETи добавьте туда строку входа.
06 / docker compose
То же самое в виде compose-файла
services:
termalin:
image: ghcr.io/termalinapp/termalin-connector:latest
restart: unless-stopped
hostname: office-nas
environment:
TERMALIN_TOKEN: ${TERMALIN_TOKEN}
TERMALIN_TARGET: 192.168.1.10:22
TERMALIN_USER: deploy
volumes:
- termalin:/data
volumes:
termalin: Чтобы достучаться до самого хоста Docker, используйте его адрес в локальной сети или, в Docker Desktop, host.docker.internal:22 (в Linux добавьте extra_hosts: ["host.docker.internal:host-gateway"]).
07 / NAS
Synology и Unraid
- ▸Synology (Container Manager): Registry → добавьте
ghcr.io/termalinapp/termalin-connector, создайте контейнер с переменными выше, том для/data, включите «auto restart». Включите SSH в Control Panel → Terminal & SNMP для терминала и задайтеTERMALIN_TARGET=<адрес NAS>:22. - ▸Unraid: Docker → Add Container, репозиторий
ghcr.io/termalinapp/termalin-connector, путь/data→/mnt/user/appdata/termalin, переменные как переменные контейнера. - ▸Папка, примонтированная через bind, должна быть доступна на запись для uid 10001 (
chown 10001:10001 /mnt/…/termalin); именованный том Docker настроит за вас.
08 / MikroTik RouterOS 7
Прямо на роутере
Пока роутеры на arm64 и x86 (сборки armv7 ещё нет). Включите пакет container и device-mode, затем:
/interface/veth add name=veth-termalin address=172.17.0.2/24 gateway=172.17.0.1
/interface/bridge/port add bridge=containers interface=veth-termalin
/container/envs add name=termalin key=TERMALIN_TOKEN value=<token>
/container/envs add name=termalin key=TERMALIN_TARGET value=192.168.88.1:22
/container/mounts add name=termalin-data src=/usb1/termalin dst=/data
/container add remote-image=ghcr.io/termalinapp/termalin-connector:latest \
interface=veth-termalin envlist=termalin mounts=termalin-data \
root-dir=/usb1/termalin-root start-on-boot=yes logging=yes Здесь предполагается бридж containers с 172.17.0.1/24 и NAT наружу, как в собственном руководстве MikroTik по контейнерам. В качестве цели укажите собственный SSH роутера (/ip/service enable ssh) или любой хост за ним.
09 / Kubernetes
Одна реплика, Secret, крошечный PVC
apiVersion: v1
kind: Secret
metadata: { name: termalin }
stringData: { token: "<token>" }
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata: { name: termalin-data }
spec:
accessModes: [ReadWriteOnce]
resources: { requests: { storage: 16Mi } }
---
apiVersion: apps/v1
kind: Deployment
metadata: { name: termalin-connector }
spec:
replicas: 1
strategy: { type: Recreate }
selector: { matchLabels: { app: termalin-connector } }
template:
metadata: { labels: { app: termalin-connector } }
spec:
securityContext: { runAsUser: 10001, runAsGroup: 10001, fsGroup: 10001, runAsNonRoot: true }
containers:
- name: connector
image: ghcr.io/termalinapp/termalin-connector:0.2.3
env:
- { name: TERMALIN_TOKEN, valueFrom: { secretKeyRef: { name: termalin, key: token } } }
- { name: TERMALIN_TARGET, value: "10.0.12.7:22" }
- { name: TERMALIN_NAME, value: "k8s-prod" }
securityContext: { readOnlyRootFilesystem: true, allowPrivilegeEscalation: false, capabilities: { drop: [ALL] } }
resources: { requests: { cpu: 10m, memory: 16Mi }, limits: { memory: 64Mi } }
volumeMounts: [{ name: data, mountPath: /data }]
volumes:
- { name: data, persistentVolumeClaim: { claimName: termalin-data } } До внутренних сервисов достаёт их кластерный адрес в веб-ссылке — http://grafana.monitoring.svc:3000 через DNS кластера разрешается в частный адрес. Держите одну реплику на одно подключение — два пода на одном томе были бы одним и тем же Connector дважды.
10 / AWS ECS
Задача Fargate или EC2, только исходящее
Сервис с desired count 1, образ выше, токен из Secrets Manager как TERMALIN_TOKEN и том EFS на /data (владелец — 10001; access point EFS с uid/gid 10001). Нужно только исходящее HTTPS до termal.in — без балансировщика и без входящего правила. Security group целей должны пропускать задачу на используемых портах (22, 3389, порты сайтов). Адрес метаданных задачи ECS отклоняется, как и любой адрес метаданных.
11 / обновления и ограничения
Скачайте новый тег; чего контейнер не умеет
- ▸Обновления. Контейнер никогда не обновляется сам — скачайте новый тег и пересоздайте его (
docker compose pull && docker compose up -dили новый тег образа в Deployment). Том сохраняет подключение. В веб-кабинете кнопки «Обновить сейчас» для него нет. - ▸Функции SSH требуют целевого сервера. Терминал, команды, файлы, беспарольные базы данных, метрики и бэкапы требуют SSH-сервера на целевом сервере и строки входа там; в самом образе SSH-сервера нет.
- ▸Один целевой SSH-сервер на Connector (
TERMALIN_TARGET); веб-ссылки и рабочие столы могут указывать на любой частный адрес. - ▸armv7 (32-битный ARM) пока не собирается.
Вопросы и ответы
Какие архитектуры и какого размера образ?
Мультиархитектурный образ для linux/amd64 и linux/arm64, около 4 МБ: статический Connector, CA-сертификаты и больше ничего — без оболочки, без пакетного менеджера, без SSH-сервера. Работает под uid 10001 и хранит конфигурацию в томе /data. armv7 (32-битный ARM) пока не собирается.
Откуда берётся образ?
Он собирается открыто, в публичном репозитории termalinapp/termalin, только из подписанных релизных бинарников, опубликованных на termal.in — каждый проверяется по манифесту релиза и его подписи, прежде чем попасть в образ.
Нужен ли SSH-сервер в контейнере или рядом с ним?
Для внутренних сайтов, удалённых рабочих столов (RDP/VNC) и страницы баз данных — нет: они идут напрямую на собственный host:port целевого сервера через Connector, так что контейнер в VPC или домашней сети может публиковать их вообще без sshd. А вот терминал, команды, файлы по SFTP, беспарольные инструменты баз данных, метрики и бэкапы требуют SSH-сервера на целевом сервере (TERMALIN_TARGET) и добавленной туда строки входа — в самом образе его нет.
Как обновить контейнер?
Контейнер никогда не обновляется сам. Скачайте новый тег и пересоздайте его — docker compose pull && docker compose up -d или новый тег образа в Deployment. Том /data сохраняет подключение, так что подключать заново не нужно. Для контейнера в веб-кабинете кнопки «Обновить сейчас» нет.
Сколько это стоит и какой тариф нужен?
Connector — облачная функция, поэтому нужен аккаунт Termalin на Pro или пробном периоде на 14 дней. Образ можно скачивать бесплатно; на число добавляемых Connector ограничений нет.
Достучитесь до всей сети из одного контейнера
Токен, один docker run, без входящего порта. На NAS, роутере, в Kubernetes или ECS.
Pro (или 14 дней бесплатно) · Внутренние сайты · Удалённые рабочие столы