termal.in

Connector · Docker

Execute o Connector em um container — sem porta de entrada.

A imagem oficial ghcr.io/termalinapp/termalin-connector executa o Connector do Termalin em um único container em qualquer máquina de uma rede — um NAS, um home lab, um roteador, um cluster Kubernetes, um serviço ECS. Ela se conecta de dentro para fora até o Termalin e alcança os servidores, sites internos e áreas de trabalho daquela rede, sem nenhuma porta de entrada aberta. Cerca de 4 MB, amd64/arm64, roda como uid 10001.

amd64 / arm64 · sem porta de entrada · Pro (ou 14 dias de teste)

01  /  por que um container

Um container na rede, nada para abrir.

Um Connector permite que o Termalin alcance uma máquina privada sem porta de entrada e sem chave de longa duração nela. Algumas máquinas são mais fáceis de adicionar como um container do que instalar um binário e um serviço — e algumas só rodam containers. A imagem serve para elas:

  • ▸Um NAS ou home lab. Synology, Unraid ou um host Docker na sua LAN — alcance o SSH da própria máquina e qualquer outro servidor, site ou área de trabalho na rede.
  • ▸Um roteador. O MikroTik RouterOS 7 roda containers; um deles abriga o Connector para o roteador e tudo o que está atrás dele.
  • ▸Kubernetes. Um Deployment de uma réplica alcança os serviços do cluster pelo endereço interno deles.
  • ▸AWS ECS / uma VPC. Uma tarefa Fargate ou EC2 apenas com HTTPS de saída — sem load balancer, sem regra de entrada — alcança instâncias privadas, sites internos e áreas de trabalho.

02  /  a imagem

Quatro megabytes, sem shell, sem servidor SSH.

A imagem é ghcr.io/termalinapp/termalin-connector:<version> (e :latest), para linux/amd64 e linux/arm64.

  • ▸Cerca de 4 MB. O Connector estático, os certificados de CA e nada mais — sem shell, sem gerenciador de pacotes, sem servidor SSH. Ela roda como uid 10001 e mantém a configuração no volume /data.
  • ▸Compilada de forma aberta. No repositório público termalinapp/termalin, apenas a partir dos binários de versão assinados em termal.in — cada um conferido contra o manifesto da versão e sua assinatura antes de entrar.
  • ▸armv7 ainda não é compilado (ARM de 32 bits). Por enquanto, apenas amd64 e arm64.

03  /  início rápido

Cadastre um container com um único docker run.

Obtenha um token de cadastro no painel web (Connectors → Adicionar), depois:

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

As variáveis:

VariávelO que faz
TERMALIN_TOKENToken de cadastro; usado só na primeira inicialização, quando o volume ainda não tem configuração.
TERMALIN_TARGEThost:port do servidor SSH para onde vão os terminais, comandos e arquivos (o host Docker ou outra máquina). Dentro do container, 127.0.0.1 é o próprio container, que não tem servidor SSH.
TERMALIN_USERUsuário de login naquele servidor SSH (padrão: o padrão da conta).
TERMALIN_NAMENome no painel web (padrão: o hostname do container — defina --hostname ou isto).
TERMALIN_SERVERPadrão: https://termal.in.

Primeira inicialização: sem configuração em /data e com um token definido, o container se cadastra, imprime a linha de login abaixo e conecta. As inicializações seguintes apenas conectam — o token pode ficar no ambiente, ele não é enviado de novo. Sem configuração e sem token, ele avisa e sai com código 1. docker stop o para na hora. Para cadastrar de novo, remova o volume e inicie com um novo token.

04  /  a linha de login

Confie no certificado no destino.

O Connector do container nunca toca no destino. No cadastro, ele imprime a linha que permite que os certificados de curta duração do Termalin para esta conta façam login — e docker exec termalin termalin-agent check a imprime de novo:

cert-authority,principals="termalin-<account id>" ssh-ed25519 AAAA… termalin-connector

Coloque-a no ~/.ssh/authorized_keys do usuário de login no destino (uma linha, arquivo em modo 600, ~/.ssh em 700). Em um servidor que você administra como root, pode em vez disso adicionar TrustedUserCAKeys e AuthorizedPrincipalsFile ao sshd_config dele — o check imprime os dois. Sem isso, terminais e comandos por este Connector são recusados pelo destino; links web e áreas de trabalho não precisam disso. O check também informa se o servidor SSH do destino responde (sshd=up); o status de login é ca=unknown, porque os arquivos do destino não podem ser lidos de dentro do container.

05  /  sem servidor SSH

Sites internos e áreas de trabalho, sem nenhum sshd.

Os sites internos e as áreas de trabalho remotas (RDP, VNC) não passam pelo SSH: o backend pede ao Connector para abrir uma conexão com o host:port do próprio site ou da própria área de trabalho, e o Connector conecta lá diretamente. Então um container em uma VPC, um serviço ECS ou uma rede doméstica pode publicar sites internos e áreas de trabalho sem nenhum servidor SSH. A página de banco de dados com uma senha de banco de dados funciona do mesmo jeito, na porta do banco.

  • ▸Apenas endereços privados. Os destinos de conexão precisam estar na rede privada — RFC 1918, loopback, link-local, CGNAT 100.64/10 (como o Tailscale), ULA de IPv6. O Connector não é um relay para a internet, e endereços de metadados de nuvem (169.254.169.254 e afins) são sempre recusados.
  • ▸Precisa de um servidor SSH no destino: o terminal, o ssh_exec e as outras ferramentas de comando, arquivos por SFTP, as ferramentas de banco de dados sem senha, métricas e backups. Defina TERMALIN_TARGET e adicione a linha de login lá.

06  /  docker compose

O mesmo, como um arquivo 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:

Para alcançar o próprio host Docker, use o endereço de LAN dele, ou no Docker Desktop host.docker.internal:22 (no Linux, adicione extra_hosts: ["host.docker.internal:host-gateway"]).

07  /  NAS

Synology e Unraid.

  • ▸Synology (Container Manager): Registry → adicione ghcr.io/termalinapp/termalin-connector, crie um container com as variáveis acima, um volume para /data, “auto restart” ligado. Ative o SSH em Control Panel → Terminal & SNMP para o terminal e defina TERMALIN_TARGET=<NAS address>:22.
  • ▸Unraid: Docker → Add Container, repositório ghcr.io/termalinapp/termalin-connector, um caminho /data → /mnt/user/appdata/termalin, as variáveis como variáveis do container.
  • ▸Uma pasta com bind mount precisa ter permissão de escrita para o uid 10001 (chown 10001:10001 /mnt/…/termalin); um volume nomeado é configurado pelo Docker para você.

08  /  MikroTik RouterOS 7

No próprio roteador.

Roteadores arm64 e x86 por enquanto (ainda sem build para armv7). Ative o pacote container e o device-mode, depois:

/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

Isso pressupõe uma bridge containers com 172.17.0.1/24 e NAT de saída, como no próprio guia de containers da MikroTik. Aponte para o SSH do próprio roteador (/ip/service enable ssh) ou para qualquer host atrás dele.

09  /  Kubernetes

Uma réplica, um Secret, um PVC minúsculo.

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 } }

Os serviços internos são alcançados pelo endereço de cluster deles em um link web — http://grafana.monitoring.svc:3000 resolve pelo DNS do cluster para um endereço privado. Mantenha uma réplica por cadastro: dois pods no mesmo volume seriam o mesmo Connector duas vezes.

10  /  AWS ECS

Uma tarefa Fargate ou EC2, só de saída.

Um serviço com desired count 1, a imagem acima, o token do Secrets Manager como TERMALIN_TOKEN e um volume EFS em /data (de propriedade do 10001 — um access point do EFS com uid/gid 10001). HTTPS de saída para termal.in é tudo o que ele precisa — sem load balancer, sem regra de entrada. Os security groups dos destinos precisam deixar a tarefa entrar nas portas usadas (22, 3389, as portas dos sites). O endereço de metadados da tarefa ECS é recusado como todo endereço de metadados.

11  /  atualizações e limites

Baixe uma nova tag; o que um container não faz.

  • ▸Atualizações. O container nunca se atualiza sozinho — baixe uma nova tag e recrie-o (docker compose pull && docker compose up -d, ou uma nova tag de imagem no Deployment). O volume mantém o cadastro. O painel web não mostra “Atualizar agora” para ele.
  • ▸Os recursos de SSH precisam de um destino. Terminal, comandos, arquivos, bancos de dados sem senha, métricas e backups precisam de um servidor SSH no destino e da linha de login lá; a imagem não tem nenhum próprio.
  • ▸Um servidor SSH de destino por Connector (TERMALIN_TARGET); links web e áreas de trabalho podem apontar para qualquer endereço privado.
  • ▸armv7 (ARM de 32 bits) ainda não é compilado.

Perguntas frequentes

Quais arquiteturas e qual o tamanho da imagem?

Uma imagem multi-arch para linux/amd64 e linux/arm64, de cerca de 4 MB: o Connector estático, os certificados de CA e nada mais — sem shell, sem gerenciador de pacotes, sem servidor SSH. Ela roda como uid 10001 e mantém a configuração no volume /data. armv7 (ARM de 32 bits) ainda não é compilado.

De onde vem a imagem?

Ela é compilada de forma aberta, no repositório público termalinapp/termalin, apenas a partir dos binários de versão assinados publicados em termal.in — cada um conferido contra o manifesto da versão e sua assinatura antes de entrar na imagem.

Preciso de um servidor SSH dentro ou ao lado do container?

Não para sites internos, áreas de trabalho remotas (RDP/VNC) nem a página de banco de dados — essas vão direto ao host:port do próprio destino pelo Connector, então um container em uma VPC ou numa rede doméstica pode publicá-las sem nenhum sshd em lugar algum. Já um terminal, comandos, arquivos por SFTP, as ferramentas de banco de dados sem senha, métricas e backups precisam de um servidor SSH no destino (TERMALIN_TARGET) e da linha de login adicionada lá — a própria imagem não tem nenhum.

Como atualizo o container?

O container nunca se atualiza sozinho. Baixe uma nova tag e recrie-o — docker compose pull && docker compose up -d, ou uma nova tag de imagem no Deployment. O volume /data mantém o cadastro, então você não cadastra de novo. O painel web não mostra “Atualizar agora” para um container.

Quanto custa e de qual plano preciso?

O Connector é um recurso hospedado, então precisa de uma conta Termalin no Pro ou nos 14 dias de teste. A imagem é gratuita para baixar; não há limite de quantos Connectors você adiciona.

Alcance a rede inteira a partir de um único container.

Um token, um docker run, sem porta de entrada. Em um NAS, um roteador, Kubernetes ou ECS.

Pro (ou 14 dias de teste) · Sites internos · Áreas de trabalho remotas