termal.in

Connector · Docker

Connector をコンテナーで実行——受信ポートなし。

公式イメージ ghcr.io/termalinapp/termalin-connector は、Termalin Connector をネットワーク上の任意のマシンで 1 つのコンテナーとして実行します——NAS、ホームラボ、ルーター、Kubernetes クラスター、ECS サービスなど。Termalin へ外向きに接続し、そのネットワーク上のサーバー、内部サイト、デスクトップに到達します。受信ポートを一切開きません。約 4 MB、amd64/arm64、uid 10001 で動作します。

amd64 / arm64 · 受信ポート不要 · Pro(または 14 日間のトライアル)

01  /  コンテナーを使う理由

ネットワーク上に 1 つのコンテナー。開放するポートなし。

Connector を使うと、受信ポートも、サーバー上に残り続ける鍵もなしで、Termalin からプライベートなマシンに到達できます。マシンによっては、バイナリとサービスをインストールするより、コンテナーとして追加するほうが簡単です。コンテナーしか動かせないマシンもあります。このイメージはそうしたマシンに適しています。

  • ▸NAS やホームラボ。LAN 上の Synology、Unraid、Docker ホストなど。そのマシン自身の SSH にも、ネットワーク上の他のサーバー・サイト・デスクトップにも到達できます。
  • ▸ルーター。MikroTik RouterOS 7 はコンテナーを動かせます。その 1 つに Connector を入れれば、ルーター自身とその背後のすべてに到達できます。
  • ▸Kubernetes。レプリカ 1 の Deployment で、クラスター内のサービスに内部アドレスで到達できます。
  • ▸AWS ECS / VPC。アウトバウンドの HTTPS だけを許可した Fargate または EC2 のタスクが——ロードバランサーも受信ルールもなしで——プライベートなインスタンス、内部サイト、デスクトップに到達します。

02  /  イメージ

4 メガバイト、シェルなし、SSH サーバーなし。

イメージは ghcr.io/termalinapp/termalin-connector:<version>(および :latest)で、linux/amd64 と linux/arm64 に対応します。

  • ▸約 4 MB。静的ビルドの Connector と CA 証明書だけで、ほかには何も入っていません——シェルも、パッケージマネージャーも、SSH サーバーもありません。uid 10001 で動作し、設定は /data ボリュームに保存します。
  • ▸公開の場でビルド。公開リポジトリ termalinapp/termalin で、termal.in に公開された署名付きのリリースバイナリだけからビルドされます。各バイナリはイメージに入る前に、リリースマニフェストとその署名に照らして検証されます。
  • ▸armv7 はまだビルドしていません(32 ビット ARM)。今のところ amd64 と arm64 のみです。

03  /  クイックスタート

1 回の 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ターミナル・コマンド・ファイルの接続先となる SSH サーバーの host:port(Docker ホスト、または別のマシン)。コンテナー内の 127.0.0.1 はコンテナー自身を指し、そこには SSH サーバーがありません。
TERMALIN_USERその SSH サーバーのログインユーザー(既定:アカウントの既定値)。
TERMALIN_NAMEキャビネットでの名前(既定:コンテナーのホスト名。--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 に追加します(1 行、ファイルのモードは 600、~/.ssh は 700)。root で管理しているサーバーなら、代わりにその sshd_config に TrustedUserCAKeys と AuthorizedPrincipalsFile を追加することもできます——check は両方を出力します。これがないと、この Connector 経由のターミナルとコマンドはターゲットに拒否されます。ウェブリンクとデスクトップには不要です。check はターゲットの SSH サーバーが応答するか(sshd=up)も報告します。サインインの状態は ca=unknown になります。コンテナー内からはターゲットのファイルを読めないためです。

05  /  SSH サーバー不要

内部サイトとデスクトップは、どこにも sshd なしで。

内部サイトとリモートデスクトップ(RDP、VNC)は SSH を経由しません。バックエンドが Connector に対して、サイトやデスクトップ自身の host:port への接続を開くよう要求し、Connector がそこへ直接つなぎます。そのため、VPC や ECS サービス、自宅ネットワークの中のコンテナーは、SSH サーバーが一切なくても内部サイトやデスクトップを公開できます。データベースパスワードを使うデータベースページも、データベースのポートに対して同じように動きます。

  • ▸プライベートアドレスのみ。接続先はプライベートネットワーク上になければなりません——RFC 1918、ループバック、リンクローカル、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 ホスト自身に到達するには、その LAN アドレスを使うか、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 用のボリュームを指定してコンテナーを作成し、「自動再起動」をオンにします。ターミナルを使うには Control Panel → Terminal & SNMP で SSH を有効にし、TERMALIN_TARGET=<NAS address>:22 を設定します。
  • ▸Unraid:Docker → Add Container で、リポジトリに ghcr.io/termalinapp/termalin-connector、パス /data → /mnt/user/appdata/termalin、変数をコンテナー変数として設定します。
  • ▸バインドマウントしたフォルダーは uid 10001 が書き込めるようにする必要があります(chown 10001:10001 /mnt/…/termalin)。名前付きボリュームなら Docker が用意してくれます。

08  /  MikroTik RouterOS 7

ルーター自身の上で。

今のところ arm64 と x86 のルーターに対応します(armv7 ビルドはまだありません)。container パッケージとデバイスモードを有効にし、次を実行します。

/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

これは、MikroTik 公式のコンテナーガイドと同じく、172.17.0.1/24 を持つブリッジ containers と外向きの NAT があることを前提としています。ルーター自身の SSH(/ip/service enable ssh)か、その背後の任意のホストを対象にできます。

09  /  Kubernetes

レプリカ 1 つ、Secret 1 つ、小さな 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 を通じてプライベートアドレスに解決されます。登録 1 つにつきレプリカは 1 つにしてください。同じボリュームを使う 2 つの Pod は、同じ Connector が二重に動くことになります。

10  /  AWS ECS

Fargate または EC2 のタスク、アウトバウンドのみ。

desired count を 1 にしたサービスに、上記のイメージ、Secrets Manager のトークンを TERMALIN_TOKEN として、そして /data に EFS ボリューム(所有者は 10001——uid/gid 10001 の EFS アクセスポイント)を設定します。必要なのは termal.in への外向きの HTTPS だけです——ロードバランサーも受信ルールも不要です。ターゲット側のセキュリティグループは、使用するポート(22、3389、各サイトのポート)でタスクからの接続を許可する必要があります。ECS のタスクメタデータアドレスは、ほかのすべてのメタデータアドレスと同様に拒否されます。

11  /  アップデートと制限

新しいタグを pull する。コンテナーにできないこと。

  • ▸アップデート。コンテナーが自分でアップデートすることはありません——新しいタグを pull してコンテナーを作り直します(docker compose pull && docker compose up -d、または Deployment の新しいイメージタグ)。ボリュームが登録情報を保持します。キャビネットにこのコンテナー用の「今すぐ更新」は表示されません。
  • ▸SSH 系の機能にはターゲットが必要。ターミナル、コマンド、ファイル、パスワード不要のデータベース、メトリクス、バックアップには、ターゲット上の SSH サーバーとそこに追加するサインイン行が必要です。イメージ自体は SSH サーバーを持ちません。
  • ▸Connector 1 つにつきターゲットの SSH サーバーは 1 つ(TERMALIN_TARGET)。ウェブリンクとデスクトップは任意のプライベートアドレスを指定できます。
  • ▸armv7(32 ビット ARM)はまだビルドしていません。

よくある質問

対応アーキテクチャとイメージのサイズは?

linux/amd64 と linux/arm64 に対応するマルチアーキテクチャのイメージで、サイズは約 4 MB です。静的ビルドの Connector と CA 証明書だけで、ほかには何も入っていません——シェルも、パッケージマネージャーも、SSH サーバーもありません。uid 10001 で動作し、設定は /data ボリュームに保存します。armv7(32 ビット ARM)はまだビルドしていません。

イメージはどこで作られていますか?

公開の場でビルドされています。公開リポジトリ termalinapp/termalin で、termal.in に公開された署名付きのリリースバイナリだけからビルドされます。各バイナリはイメージに入る前に、リリースマニフェストとその署名に照らして検証されます。

コンテナーの中や隣に SSH サーバーは必要ですか?

内部サイト、リモートデスクトップ(RDP/VNC)、データベースページには不要です——これらは Connector を通じてターゲット自身の host:port に直接つながるので、VPC や自宅ネットワークの中のコンテナーは どこにも sshd なしで公開できます。一方、ターミナル、コマンド、SFTP のファイル、パスワード不要のデータベースツール、メトリクス、バックアップには、ターゲット(TERMALIN_TARGET)上の SSH サーバーと、そこに追加するサインイン行が必要です。イメージ自体には SSH サーバーがありません。

コンテナーはどうやってアップデートしますか?

コンテナーが自分でアップデートすることはありません。新しいタグを pull して作り直します——docker compose pull && docker compose up -d、または Deployment の新しいイメージタグです。/data ボリュームが登録情報を保持するので、登録をやり直す必要はありません。キャビネットにコンテナー用の「今すぐ更新」は表示されません。

費用はいくらで、どのプランが必要ですか?

Connector はホスト型の機能なので、Pro または 14 日間のトライアルの Termalin アカウントが必要です。イメージの pull は無料で、追加できる Connector の数に上限はありません。

1 つのコンテナーからネットワーク全体へ。

トークン 1 つ、docker run 1 回、受信ポートなし。NAS、ルーター、Kubernetes、ECS の上で。

Pro(または 14 日間のトライアル) · 内部サイト · リモートデスクトップ